From f99e3582bd9838a36883a73380b1d0315cda76e8 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Sun, 7 Nov 2021 20:37:34 -0600 Subject: [PATCH 01/16] Merge commit 'ea199bacef07213dbe008841b89c450e3bf0c638' into rustfmt-sync --- .github/workflows/rustdoc_check.yml | 25 +++ Configurations.md | 19 +- Contributing.md | 2 +- README.md | 23 +- appveyor.yml | 8 - intellij.md | 23 +- legacy-rustfmt.toml | 2 - rust-toolchain | 2 +- src/attr.rs | 4 +- src/attr/doc_comment.rs | 2 +- src/bin/main.rs | 2 +- src/cargo-fmt/main.rs | 6 +- src/chains.rs | 4 +- src/comment.rs | 18 +- src/config/options.rs | 4 +- src/emitter/checkstyle.rs | 4 +- src/emitter/diff.rs | 2 +- src/expr.rs | 21 +- src/format-diff/main.rs | 2 +- src/formatting.rs | 4 +- src/git-rustfmt/main.rs | 2 +- src/imports.rs | 4 +- src/items.rs | 208 +++++++++--------- src/lib.rs | 4 +- src/lists.rs | 4 +- src/macros.rs | 16 +- src/matches.rs | 12 +- src/modules.rs | 16 +- src/overflow.rs | 2 +- src/pairs.rs | 16 +- src/patterns.rs | 8 +- src/reorder.rs | 4 +- src/syntux/parser.rs | 18 +- src/syntux/session.rs | 2 +- src/test/mod.rs | 4 +- src/test/mod_resolver.rs | 42 +++- src/types.rs | 4 +- src/utils.rs | 6 +- src/visitor.rs | 197 ++++++----------- tests/mod-resolver/issue-5063/foo.rs | 2 + tests/mod-resolver/issue-5063/foo/bar/baz.rs | 1 + tests/mod-resolver/issue-5063/main.rs | 5 + .../group_imports/One-merge_imports.rs | 17 ++ .../configs/group_imports/One-nested.rs | 7 + .../configs/group_imports/One-no_reorder.rs | 16 ++ tests/source/configs/group_imports/One.rs | 15 ++ tests/source/empty-item-single-line-false.rs | 46 ++++ .../item-brace-style-always-next-line.rs | 35 +++ .../group_imports/One-merge_imports.rs | 14 ++ .../configs/group_imports/One-nested.rs | 6 + .../configs/group_imports/One-no_reorder.rs | 12 + tests/target/configs/group_imports/One.rs | 11 + tests/target/empty-item-single-line-false.rs | 41 ++++ .../issue-5012/trailing_comma_always.rs | 8 + .../target/issue-5012/trailing_comma_never.rs | 8 + tests/target/issue-5033/minimum_example.rs | 8 + tests/target/issue-5033/nested_modules.rs | 11 + tests/target/issue_4850.rs | 4 + .../item-brace-style-always-next-line.rs | 29 +++ 59 files changed, 670 insertions(+), 372 deletions(-) create mode 100644 .github/workflows/rustdoc_check.yml delete mode 100644 appveyor.yml delete mode 100644 legacy-rustfmt.toml create mode 100644 tests/mod-resolver/issue-5063/foo.rs create mode 100644 tests/mod-resolver/issue-5063/foo/bar/baz.rs create mode 100644 tests/mod-resolver/issue-5063/main.rs create mode 100644 tests/source/configs/group_imports/One-merge_imports.rs create mode 100644 tests/source/configs/group_imports/One-nested.rs create mode 100644 tests/source/configs/group_imports/One-no_reorder.rs create mode 100644 tests/source/configs/group_imports/One.rs create mode 100644 tests/source/empty-item-single-line-false.rs create mode 100644 tests/target/configs/group_imports/One-merge_imports.rs create mode 100644 tests/target/configs/group_imports/One-nested.rs create mode 100644 tests/target/configs/group_imports/One-no_reorder.rs create mode 100644 tests/target/configs/group_imports/One.rs create mode 100644 tests/target/empty-item-single-line-false.rs create mode 100644 tests/target/issue-5012/trailing_comma_always.rs create mode 100644 tests/target/issue-5012/trailing_comma_never.rs create mode 100644 tests/target/issue-5033/minimum_example.rs create mode 100644 tests/target/issue-5033/nested_modules.rs create mode 100644 tests/target/issue_4850.rs diff --git a/.github/workflows/rustdoc_check.yml b/.github/workflows/rustdoc_check.yml new file mode 100644 index 0000000000000..ca96d30f58639 --- /dev/null +++ b/.github/workflows/rustdoc_check.yml @@ -0,0 +1,25 @@ +name: rustdoc check +on: + push: + branches: + - master + pull_request: + +jobs: + rustdoc_check: + runs-on: ubuntu-latest + name: rustdoc check + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: install rustup + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh + sh rustup-init.sh -y --default-toolchain none + rustup target add x86_64-unknown-linux-gnu + + - name: document rustfmt + env: + RUSTDOCFLAGS: --document-private-items --enable-index-page --show-type-layout --generate-link-to-definition -Zunstable-options -Dwarnings + run: cargo doc -Zskip-rustdoc-fingerprint --no-deps -p rustfmt-nightly -p rustfmt-config_proc_macro diff --git a/Configurations.md b/Configurations.md index 7a77dbe154b60..13826883d2f4b 100644 --- a/Configurations.md +++ b/Configurations.md @@ -2062,7 +2062,7 @@ use sit; Controls the strategy for how imports are grouped together. - **Default value**: `Preserve` -- **Possible values**: `Preserve`, `StdExternalCrate` +- **Possible values**: `Preserve`, `StdExternalCrate`, `One` - **Stable**: No #### `Preserve` (default): @@ -2108,6 +2108,23 @@ use super::update::convert_publish_payload; use crate::models::Event; ``` +#### `One`: + +Discard existing import groups, and create a single group for everything + +```rust +use super::schema::{Context, Payload}; +use super::update::convert_publish_payload; +use crate::models::Event; +use alloc::alloc::Layout; +use broker::database::PooledConnection; +use chrono::Utc; +use core::f32; +use juniper::{FieldError, FieldResult}; +use std::sync::Arc; +use uuid::Uuid; +``` + ## `reorder_modules` Reorder `mod` declarations alphabetically in group. diff --git a/Contributing.md b/Contributing.md index e6dc6a220376d..3073996019ee2 100644 --- a/Contributing.md +++ b/Contributing.md @@ -59,7 +59,7 @@ example, the `issue-1111.rs` test file is configured by the file ## Debugging Some `rewrite_*` methods use the `debug!` macro for printing useful information. -These messages can be printed by using the environment variable `RUST_LOG=rustfmt=DEBUG`. +These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`. These traces can be helpful in understanding which part of the code was used and get a better grasp on the execution flow. diff --git a/README.md b/README.md index 9c7a1c4bc341b..b3d21e6fb87c7 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ cargo +nightly fmt ## Limitations -Rustfmt tries to work on as much Rust code as possible, sometimes, the code +Rustfmt tries to work on as much Rust code as possible. Sometimes, the code doesn't even need to compile! As we approach a 1.0 release we are also looking to limit areas of instability; in particular, post-1.0, the formatting of most code should not change as Rustfmt improves. However, there are some things that @@ -102,6 +102,25 @@ read data from stdin. Alternatively, you can use `cargo fmt` to format all binary and library targets of your crate. You can run `rustfmt --help` for information about available arguments. +The easiest way to run rustfmt against a project is with `cargo fmt`. `cargo fmt` works on both +single-crate projects and [cargo workspaces](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html). +Please see `cargo fmt --help` for usage information. + +You can specify the path to your own `rustfmt` binary for cargo to use by setting the`RUSTFMT` +environment variable. This was added in v1.4.22, so you must have this version or newer to leverage this feature (`cargo fmt --version`) + +### Running `rustfmt` directly + +To format individual files or arbitrary codes from stdin, the `rustfmt` binary should be used. Some +examples follow: + +- `rustfmt lib.rs main.rs` will format "lib.rs" and "main.rs" in place +- `rustfmt` will read a code from stdin and write formatting to stdout + - `echo "fn main() {}" | rustfmt` would emit "fn main() {}". + +For more information, including arguments and emit options, see `rustfmt --help`. + +### Verifying code is formatted When running with `--check`, Rustfmt will exit with `0` if Rustfmt would not make any formatting changes to the input, and `1` if Rustfmt would make changes. @@ -129,7 +148,7 @@ rustfmt to exit with an error code if the input is not formatted correctly. It will also print any found differences. (Older versions of Rustfmt don't support `--check`, use `--write-mode diff`). -A minimal Travis setup could look like this (requires Rust 1.24.0 or greater): +A minimal Travis setup could look like this (requires Rust 1.31.0 or greater): ```yaml language: rust diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b3dda091e0a96..0000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,8 +0,0 @@ -environment: - global: - PROJECT_NAME: rustfmt - -build: false - -test_script: - - echo Why does no one have access to delete me? diff --git a/intellij.md b/intellij.md index 7aea6222b8bc5..6a711c0171aeb 100644 --- a/intellij.md +++ b/intellij.md @@ -3,19 +3,28 @@ ## Installation - Install [CLion](https://www.jetbrains.com/clion/), [IntelliJ Ultimate or CE](https://www.jetbrains.com/idea/) through the direct download link or using the [JetBrains Toolbox](https://www.jetbrains.com/toolbox/). - CLion provides a built-in debugger interface but its not free like IntelliJ CE - which does not provide the debugger interface. (IntelliJ seems to lack the toolchain for that, see this discussion [intellij-rust/issues/535](/~https://github.com/intellij-rust/intellij-rust/issues/535)) - -- Install the [Rust Plugin](https://intellij-rust.github.io/) by navigating to File -> Settings -> Plugins and press "Install JetBrains Plugin" - ![plugins](https://user-images.githubusercontent.com/1133787/47240861-f40af680-d3e9-11e8-9b82-cdd5c8d5f5b8.png) + CLion and IntelliJ Ultimate [provide a built-in debugger interface](/~https://github.com/intellij-rust/intellij-rust#compatible-ides) but they are not free like IntelliJ CE. + +- Install the [Rust Plugin](https://intellij-rust.github.io/) by navigating to File → Settings → Plugins and searching the plugin in the Marketplace + ![plugins](https://user-images.githubusercontent.com/6505554/83944518-6f1e5c00-a81d-11ea-9c35-e16948811ba8.png) -- Press "Install" on the rust plugin - ![install rust](https://user-images.githubusercontent.com/1133787/47240803-c0c86780-d3e9-11e8-9265-22f735e4d7ed.png) +- Press "Install" on the Rust plugin + ![install rust](https://user-images.githubusercontent.com/6505554/83944533-82c9c280-a81d-11ea-86b3-ee2e31bc7d12.png) - Restart CLion/IntelliJ ## Configuration -- Open the settings window (File -> Settings) and search for "reformat" +### Run Rustfmt on save + +- Open Rustfmt settings (File → Settings → Languages & Frameworks → Rust → Rustfmt) and enable "Run rustfmt on Save" + ![run_rustfmt_on_save](https://user-images.githubusercontent.com/6505554/83944610-3468f380-a81e-11ea-9c34-0cbd18dd4969.png) + +- IntellJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually + +### Bind shortcut to "Reformat File with Rustfmt" action + +- Open the settings window (File → Settings) and search for "reformat" ![keymap](https://user-images.githubusercontent.com/1133787/47240922-2ae10c80-d3ea-11e8-9d8f-c798d9749240.png) - Right-click on "Reformat File with Rustfmt" and assign a keyboard shortcut diff --git a/legacy-rustfmt.toml b/legacy-rustfmt.toml deleted file mode 100644 index f976fa68e4c7d..0000000000000 --- a/legacy-rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -indent_style = "Visual" -combine_control_expr = false diff --git a/rust-toolchain b/rust-toolchain index b19ecbdb07c4f..1d2cad6675117 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-10-20" +channel = "nightly-2021-11-08" components = ["rustc-dev"] diff --git a/src/attr.rs b/src/attr.rs index a5982820e3ded..76b66e9da8098 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -451,7 +451,7 @@ impl Rewrite for [ast::Attribute] { if next.is_doc_comment() { let snippet = context.snippet(missing_span); let (_, mlb) = has_newlines_before_after_comment(snippet); - result.push_str(&mlb); + result.push_str(mlb); } } result.push('\n'); @@ -484,7 +484,7 @@ impl Rewrite for [ast::Attribute] { if next.is_doc_comment() { let snippet = context.snippet(missing_span); let (_, mlb) = has_newlines_before_after_comment(snippet); - result.push_str(&mlb); + result.push_str(mlb); } } result.push('\n'); diff --git a/src/attr/doc_comment.rs b/src/attr/doc_comment.rs index c3dcb84c9488d..f653a12a8afeb 100644 --- a/src/attr/doc_comment.rs +++ b/src/attr/doc_comment.rs @@ -77,7 +77,7 @@ mod tests { ) { assert_eq!( expected_comment, - format!("{}", DocCommentFormatter::new(&literal, style)) + format!("{}", DocCommentFormatter::new(literal, style)) ); } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 1bcc5c0dada3b..9d2e97c9479fc 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -20,7 +20,7 @@ use crate::rustfmt::{ }; fn main() { - env_logger::init(); + env_logger::Builder::from_env("RUSTFMT_LOG").init(); let opts = make_opts(); let exit_code = match execute(&opts) { diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index 1d423ac34919b..759b21218c353 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -401,12 +401,12 @@ fn get_targets_root_only( fn get_targets_recursive( manifest_path: Option<&Path>, - mut targets: &mut BTreeSet, + targets: &mut BTreeSet, visited: &mut BTreeSet, ) -> Result<(), io::Error> { let metadata = get_cargo_metadata(manifest_path)?; for package in &metadata.packages { - add_targets(&package.targets, &mut targets); + add_targets(&package.targets, targets); // Look for local dependencies using information available since cargo v1.51 // It's theoretically possible someone could use a newer version of rustfmt with @@ -427,7 +427,7 @@ fn get_targets_recursive( .any(|p| p.manifest_path.eq(&manifest_path)) { visited.insert(dependency.name.to_owned()); - get_targets_recursive(Some(&manifest_path), &mut targets, visited)?; + get_targets_recursive(Some(&manifest_path), targets, visited)?; } } } diff --git a/src/chains.rs b/src/chains.rs index 614638ea2abfb..e26e24ec55ad6 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -568,7 +568,7 @@ impl<'a> ChainFormatterShared<'a> { } else { self.rewrites .iter() - .map(|rw| utils::unicode_str_width(&rw)) + .map(|rw| utils::unicode_str_width(rw)) .sum() } + last.tries; let one_line_budget = if self.child_count == 1 { @@ -673,7 +673,7 @@ impl<'a> ChainFormatterShared<'a> { ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector), _ => result.push_str(&connector), } - result.push_str(&rewrite); + result.push_str(rewrite); } Some(result) diff --git a/src/comment.rs b/src/comment.rs index dc4f4516252b1..7b76c232937dc 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -405,7 +405,7 @@ impl CodeBlockAttribute { /// attributes are valid rust attributes /// See fn new(attributes: &str) -> CodeBlockAttribute { - for attribute in attributes.split(",") { + for attribute in attributes.split(',') { match attribute.trim() { "" | "rust" | "should_panic" | "no_run" | "edition2015" | "edition2018" | "edition2021" => (), @@ -563,7 +563,7 @@ impl<'a> CommentRewrite<'a> { result.push_str(line); result.push_str(match iter.peek() { Some(next_line) if next_line.is_empty() => sep.trim_end(), - Some(..) => &sep, + Some(..) => sep, None => "", }); } @@ -622,7 +622,7 @@ impl<'a> CommentRewrite<'a> { let is_last = i == count_newlines(orig); if let Some(ref mut ib) = self.item_block { - if ib.add_line(&line) { + if ib.add_line(line) { return false; } self.is_prev_line_multi_line = false; @@ -684,8 +684,8 @@ impl<'a> CommentRewrite<'a> { self.item_block = None; if let Some(stripped) = line.strip_prefix("```") { self.code_block_attr = Some(CodeBlockAttribute::new(stripped)) - } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(&line) { - let ib = ItemizedBlock::new(&line); + } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(line) { + let ib = ItemizedBlock::new(line); self.item_block = Some(ib); return false; } @@ -941,7 +941,7 @@ fn left_trim_comment_line<'a>(line: &'a str, style: &CommentStyle<'_>) -> (&'a s { (&line[4..], true) } else if let CommentStyle::Custom(opener) = *style { - if let Some(ref stripped) = line.strip_prefix(opener) { + if let Some(stripped) = line.strip_prefix(opener) { (stripped, true) } else { (&line[opener.trim_end().len()..], false) @@ -1384,7 +1384,7 @@ impl<'a> Iterator for LineClasses<'a> { None => unreachable!(), }; - while let Some((kind, c)) = self.base.next() { + for (kind, c) in self.base.by_ref() { // needed to set the kind of the ending character on the last line self.kind = kind; if c == '\n' { @@ -1570,7 +1570,7 @@ pub(crate) fn recover_comment_removed( context.parse_sess.span_to_filename(span), vec![FormattingError::from_span( span, - &context.parse_sess, + context.parse_sess, ErrorKind::LostComment, )], ); @@ -1675,7 +1675,7 @@ impl<'a> Iterator for CommentReducer<'a> { fn remove_comment_header(comment: &str) -> &str { if comment.starts_with("///") || comment.starts_with("//!") { &comment[3..] - } else if let Some(ref stripped) = comment.strip_prefix("//") { + } else if let Some(stripped) = comment.strip_prefix("//") { stripped } else if (comment.starts_with("/**") && !comment.starts_with("/**/")) || comment.starts_with("/*!") diff --git a/src/config/options.rs b/src/config/options.rs index e92f8e8a53152..bce9e5d07f267 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -20,7 +20,7 @@ pub enum NewlineStyle { Windows, /// Force CR (`\n). Unix, - /// `\r\n` in Windows, `\n`` on other platforms. + /// `\r\n` in Windows, `\n` on other platforms. Native, } @@ -112,6 +112,8 @@ pub enum GroupImportsTactic { /// 2. other imports /// 3. `self` / `crate` / `super` imports StdExternalCrate, + /// Discard existing groups, and create a single group for everything + One, } #[config_type] diff --git a/src/emitter/checkstyle.rs b/src/emitter/checkstyle.rs index 4448214f3ff2c..76f2527db3dad 100644 --- a/src/emitter/checkstyle.rs +++ b/src/emitter/checkstyle.rs @@ -121,7 +121,7 @@ mod tests { format!(r#""#, bin_file), format!( r#""#, - XmlEscaped(&r#" println!("Hello, world!");"#), + XmlEscaped(r#" println!("Hello, world!");"#), ), String::from(""), ]; @@ -129,7 +129,7 @@ mod tests { format!(r#""#, lib_file), format!( r#""#, - XmlEscaped(&r#" println!("Greetings!");"#), + XmlEscaped(r#" println!("Greetings!");"#), ), String::from(""), ]; diff --git a/src/emitter/diff.rs b/src/emitter/diff.rs index 2fbbfedb566d1..7264ad8bbf365 100644 --- a/src/emitter/diff.rs +++ b/src/emitter/diff.rs @@ -23,7 +23,7 @@ impl Emitter for DiffEmitter { }: FormattedFile<'_>, ) -> Result { const CONTEXT_SIZE: usize = 3; - let mismatch = make_diff(&original_text, formatted_text, CONTEXT_SIZE); + let mismatch = make_diff(original_text, formatted_text, CONTEXT_SIZE); let has_diff = !mismatch.is_empty(); if has_diff { diff --git a/src/expr.rs b/src/expr.rs index 7f1dd363f9379..58942e442de05 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -257,7 +257,7 @@ pub(crate) fn format_expr( } _ => false, }, - ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, &expr), + ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr), _ => false, } } @@ -423,7 +423,7 @@ fn rewrite_empty_block( prefix: &str, shape: Shape, ) -> Option { - if block_has_statements(&block) { + if block_has_statements(block) { return None; } @@ -1148,7 +1148,7 @@ pub(crate) fn is_empty_block( block: &ast::Block, attrs: Option<&[ast::Attribute]>, ) -> bool { - !block_has_statements(&block) + !block_has_statements(block) && !block_contains_comment(context, block) && attrs.map_or(true, |a| inner_attributes(a).is_empty()) } @@ -1207,11 +1207,11 @@ fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) - let span = lit.span; let symbol = lit.token.symbol.as_str(); - if symbol.starts_with("0x") { + if let Some(symbol_stripped) = symbol.strip_prefix("0x") { let hex_lit = match context.config.hex_literal_case() { HexLiteralCase::Preserve => None, - HexLiteralCase::Upper => Some(symbol[2..].to_ascii_uppercase()), - HexLiteralCase::Lower => Some(symbol[2..].to_ascii_lowercase()), + HexLiteralCase::Upper => Some(symbol_stripped.to_ascii_uppercase()), + HexLiteralCase::Lower => Some(symbol_stripped.to_ascii_lowercase()), }; if let Some(hex_lit) = hex_lit { return wrap_str( @@ -1621,7 +1621,7 @@ fn rewrite_struct_lit<'a>( }; let fields_str = - wrap_struct_field(context, &attrs, &fields_str, shape, v_shape, one_line_width)?; + wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?; Some(format!("{} {{{}}}", path_str, fields_str)) // FIXME if context.config.indent_style() == Visual, but we run out @@ -1888,7 +1888,7 @@ pub(crate) fn rewrite_assign_rhs_expr( shape: Shape, rhs_tactics: RhsTactics, ) -> Option { - let last_line_width = last_line_width(&lhs).saturating_sub(if lhs.contains('\n') { + let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') { shape.indent.width() } else { 0 @@ -1947,7 +1947,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments, R: Rewrite>( if contains_comment { let rhs = rhs.trim_start(); - combine_strs_with_missing_comments(context, &lhs, &rhs, between_span, shape, allow_extend) + combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend) } else { Some(lhs + &rhs) } @@ -1962,6 +1962,9 @@ fn choose_rhs( has_rhs_comment: bool, ) -> Option { match orig_rhs { + Some(ref new_str) if new_str.is_empty() => { + return Some(String::new()); + } Some(ref new_str) if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width => { diff --git a/src/format-diff/main.rs b/src/format-diff/main.rs index c751932273b0a..655aeda42bf28 100644 --- a/src/format-diff/main.rs +++ b/src/format-diff/main.rs @@ -64,7 +64,7 @@ pub struct Opts { } fn main() { - env_logger::init(); + env_logger::Builder::from_env("RUSTFMT_LOG").init(); let opts = Opts::from_args(); if let Err(e) = run(opts) { println!("{}", e); diff --git a/src/formatting.rs b/src/formatting.rs index 9ef47b887cadb..7d0facb8f12cf 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -155,7 +155,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { let snippet_provider = self.parse_session.snippet_provider(module.span); let mut visitor = FmtVisitor::from_parse_sess( &self.parse_session, - &self.config, + self.config, &snippet_provider, self.report.clone(), ); @@ -180,7 +180,7 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> { &mut visitor.buffer, &path, &visitor.skipped_range.borrow(), - &self.config, + self.config, &self.report, ); diff --git a/src/git-rustfmt/main.rs b/src/git-rustfmt/main.rs index 16f5d1dd4f234..579778edbe742 100644 --- a/src/git-rustfmt/main.rs +++ b/src/git-rustfmt/main.rs @@ -170,7 +170,7 @@ impl Config { } fn main() { - env_logger::init(); + env_logger::Builder::from_env("RUSTFMT_LOG").init(); let opts = make_opts(); let matches = opts diff --git a/src/imports.rs b/src/imports.rs index 5ac799366894d..40e0d06f99df8 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -275,7 +275,7 @@ impl UseTree { shape: Shape, ) -> Option { let vis = self.visibility.as_ref().map_or(Cow::from(""), |vis| { - crate::utils::format_visibility(context, &vis) + crate::utils::format_visibility(context, vis) }); let use_str = self .rewrite(context, shape.offset_left(vis.len())?) @@ -929,7 +929,7 @@ impl Rewrite for UseTree { fn rewrite(&self, context: &RewriteContext<'_>, mut shape: Shape) -> Option { let mut result = String::with_capacity(256); let mut iter = self.path.iter().peekable(); - while let Some(ref segment) = iter.next() { + while let Some(segment) = iter.next() { let segment_str = segment.rewrite(context, shape)?; result.push_str(&segment_str); if iter.peek().is_some() { diff --git a/src/items.rs b/src/items.rs index c828798d93311..50121a8b6b50e 100644 --- a/src/items.rs +++ b/src/items.rs @@ -226,7 +226,7 @@ impl<'a> FnSig<'a> { fn to_str(&self, context: &RewriteContext<'_>) -> String { let mut result = String::with_capacity(128); // Vis defaultness constness unsafety abi. - result.push_str(&*format_visibility(context, &self.visibility)); + result.push_str(&*format_visibility(context, self.visibility)); result.push_str(format_defaultness(self.defaultness)); result.push_str(format_constness(self.constness)); result.push_str(format_async(&self.is_async)); @@ -1127,12 +1127,24 @@ pub(crate) fn format_trait( } } + let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi()); + let snippet = context.snippet(block_span); + let open_pos = snippet.find_uncommented("{")? + 1; + match context.config.brace_style() { _ if last_line_contains_single_line_comment(&result) || last_line_width(&result) + 2 > context.budget(offset.width()) => { result.push_str(&offset.to_string_with_newline(context.config)); } + _ if context.config.empty_item_single_line() + && items.is_empty() + && !result.contains('\n') + && !contains_comment(&snippet[open_pos..]) => + { + result.push_str(" {}"); + return Some(result); + } BraceStyle::AlwaysNextLine => { result.push_str(&offset.to_string_with_newline(context.config)); } @@ -1149,9 +1161,6 @@ pub(crate) fn format_trait( } result.push('{'); - let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi()); - let snippet = context.snippet(block_span); - let open_pos = snippet.find_uncommented("{")? + 1; let outer_indent_str = offset.block_only().to_string_with_newline(context.config); if !items.is_empty() || contains_comment(&snippet[open_pos..]) { @@ -1181,18 +1190,6 @@ pub(crate) fn format_trait( } } -struct OpaqueTypeBounds<'a> { - generic_bounds: &'a ast::GenericBounds, -} - -impl<'a> Rewrite for OpaqueTypeBounds<'a> { - fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - self.generic_bounds - .rewrite(context, shape) - .map(|s| format!("impl {}", s)) - } -} - pub(crate) struct TraitAliasBounds<'a> { generic_bounds: &'a ast::GenericBounds, generics: &'a ast::Generics, @@ -1225,7 +1222,7 @@ impl<'a> Rewrite for TraitAliasBounds<'a> { } else if fits_single_line { Cow::from(" ") } else { - shape.indent.to_string_with_newline(&context.config) + shape.indent.to_string_with_newline(context.config) }; Some(format!("{}{}{}", generic_bounds_str, space, where_str)) @@ -1243,7 +1240,7 @@ pub(crate) fn format_trait_alias( let alias = rewrite_ident(context, ident); // 6 = "trait ", 2 = " =" let g_shape = shape.offset_left(6)?.sub_width(2)?; - let generics_str = rewrite_generics(context, &alias, generics, g_shape)?; + let generics_str = rewrite_generics(context, alias, generics, g_shape)?; let vis_str = format_visibility(context, vis); let lhs = format!("{}trait {} =", vis_str, generics_str); // 1 = ";" @@ -1391,7 +1388,7 @@ fn format_empty_struct_or_tuple( closer: &str, ) { // 3 = " {}" or "();" - let used_width = last_line_used_width(&result, offset.width()) + 3; + let used_width = last_line_used_width(result, offset.width()) + 3; if used_width > context.config.max_width() { result.push_str(&offset.to_string_with_newline(context.config)) } @@ -1514,17 +1511,84 @@ fn format_tuple_struct( Some(result) } -pub(crate) fn rewrite_type( - context: &RewriteContext<'_>, +pub(crate) enum ItemVisitorKind<'a> { + Item(&'a ast::Item), + AssocTraitItem(&'a ast::AssocItem), + AssocImplItem(&'a ast::AssocItem), + ForeignItem(&'a ast::ForeignItem), +} + +struct TyAliasRewriteInfo<'c, 'g>( + &'c RewriteContext<'c>, + Indent, + &'g ast::Generics, + symbol::Ident, + Span, +); + +pub(crate) fn rewrite_type_alias<'a, 'b>( + ty_alias_kind: &ast::TyAlias, + context: &RewriteContext<'a>, indent: Indent, - ident: symbol::Ident, - vis: &ast::Visibility, - generics: &ast::Generics, + visitor_kind: &ItemVisitorKind<'b>, + span: Span, +) -> Option { + use ItemVisitorKind::*; + + let ast::TyAlias { + defaultness, + ref generics, + ref bounds, + ref ty, + } = *ty_alias_kind; + let ty_opt = ty.as_ref().map(|t| &**t); + let (ident, vis) = match visitor_kind { + Item(i) => (i.ident, &i.vis), + AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis), + ForeignItem(i) => (i.ident, &i.vis), + }; + let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span); + + // Type Aliases are formatted slightly differently depending on the context + // in which they appear, whether they are opaque, and whether they are associated. + // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html + // /~https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases + match (visitor_kind, ty_opt) { + (Item(_), None) => { + let op_ty = OpaqueType { bounds }; + rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis) + } + (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis), + (AssocImplItem(_), _) => { + let result = if let Some(ast::Ty { + kind: ast::TyKind::ImplTrait(_, ref bounds), + .. + }) = ty_opt + { + let op_ty = OpaqueType { bounds }; + rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY) + } else { + rewrite_ty(rw_info, None, ty.as_ref(), vis) + }?; + match defaultness { + ast::Defaultness::Default(..) => Some(format!("default {}", result)), + _ => Some(result), + } + } + (AssocTraitItem(_), _) | (ForeignItem(_), _) => { + rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis) + } + } +} + +fn rewrite_ty( + rw_info: &TyAliasRewriteInfo<'_, '_>, generic_bounds_opt: Option<&ast::GenericBounds>, rhs: Option<&R>, - span: Span, + vis: &ast::Visibility, ) -> Option { let mut result = String::with_capacity(128); + let TyAliasRewriteInfo(context, indent, generics, ident, span) = *rw_info; result.push_str(&format!("{}type ", format_visibility(context, vis))); let ident_str = rewrite_ident(context, ident); @@ -1612,28 +1676,6 @@ pub(crate) fn rewrite_type( } } -pub(crate) fn rewrite_opaque_type( - context: &RewriteContext<'_>, - indent: Indent, - ident: symbol::Ident, - generic_bounds: &ast::GenericBounds, - generics: &ast::Generics, - vis: &ast::Visibility, - span: Span, -) -> Option { - let opaque_type_bounds = OpaqueTypeBounds { generic_bounds }; - rewrite_type( - context, - indent, - ident, - vis, - generics, - Some(generic_bounds), - Some(&opaque_type_bounds), - span, - ) -} - fn type_annotation_spacing(config: &Config) -> (&str, &str) { ( if config.space_before_colon() { " " } else { "" }, @@ -1871,42 +1913,6 @@ impl<'a> Rewrite for OpaqueType<'a> { } } -pub(crate) fn rewrite_impl_type( - ident: symbol::Ident, - vis: &ast::Visibility, - defaultness: ast::Defaultness, - ty_opt: Option<&ptr::P>, - generics: &ast::Generics, - context: &RewriteContext<'_>, - indent: Indent, - span: Span, -) -> Option { - // Opaque type - let result = if let Some(rustc_ast::ast::Ty { - kind: ast::TyKind::ImplTrait(_, ref bounds), - .. - }) = ty_opt.map(|t| &**t) - { - rewrite_type( - context, - indent, - ident, - &DEFAULT_VISIBILITY, - generics, - None, - Some(&OpaqueType { bounds }), - span, - ) - } else { - rewrite_type(context, indent, ident, vis, generics, None, ty_opt, span) - }?; - - match defaultness { - ast::Defaultness::Default(..) => Some(format!("default {}", result)), - _ => Some(result), - } -} - impl Rewrite for ast::FnRetTy { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { match *self { @@ -2071,7 +2077,7 @@ fn rewrite_explicit_self( )?; Some(combine_strs_with_missing_comments( context, - ¶m_attrs, + param_attrs, &format!("&{} {}self", lifetime_str, mut_str), span, shape, @@ -2080,7 +2086,7 @@ fn rewrite_explicit_self( } None => Some(combine_strs_with_missing_comments( context, - ¶m_attrs, + param_attrs, &format!("&{}self", mut_str), span, shape, @@ -2096,7 +2102,7 @@ fn rewrite_explicit_self( Some(combine_strs_with_missing_comments( context, - ¶m_attrs, + param_attrs, &format!("{}self: {}", format_mutability(mutability), type_str), span, shape, @@ -2105,7 +2111,7 @@ fn rewrite_explicit_self( } ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments( context, - ¶m_attrs, + param_attrs, &format!("{}self", format_mutability(mutability)), span, shape, @@ -2231,7 +2237,7 @@ fn rewrite_fn_base( } // Skip `pub(crate)`. - let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span); + let lo_after_visibility = get_bytepos_after_visibility(fn_sig.visibility, span); // A conservative estimation, the goal is to be over all parens in generics let params_start = fn_sig .generics @@ -2989,7 +2995,7 @@ fn format_header( let mut result = String::with_capacity(128); let shape = Shape::indented(offset, context.config); - result.push_str(&format_visibility(context, vis).trim()); + result.push_str(format_visibility(context, vis).trim()); // Check for a missing comment between the visibility and the item name. let after_vis = vis.span.hi(); @@ -3010,7 +3016,7 @@ fn format_header( } } - result.push_str(&rewrite_ident(context, ident)); + result.push_str(rewrite_ident(context, ident)); result } @@ -3177,23 +3183,9 @@ impl Rewrite for ast::ForeignItem { // 1 = ; rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";") } - ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => { - let ast::TyAlias { - ref generics, - ref bounds, - ref ty, - .. - } = **ty_alias_kind; - rewrite_type( - &context, - shape.indent, - self.ident, - &self.vis, - generics, - Some(bounds), - ty.as_ref(), - self.span, - ) + ast::ForeignItemKind::TyAlias(ref ty_alias) => { + let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span); + rewrite_type_alias(ty_alias, context, shape.indent, kind, span) } ast::ForeignItemKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Item) @@ -3243,7 +3235,7 @@ fn rewrite_attrs( combine_strs_with_missing_comments( context, &attrs_str, - &item_str, + item_str, missed_span, shape, allow_extend, diff --git a/src/lib.rs b/src/lib.rs index 47a7b9d4dbe3c..792a1080f0e92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -283,7 +283,7 @@ impl FormatReport { writeln!( t, "{}", - FormatReportFormatterBuilder::new(&self) + FormatReportFormatterBuilder::new(self) .enable_colors(true) .build() )?; @@ -297,7 +297,7 @@ impl FormatReport { impl fmt::Display for FormatReport { // Prints all the formatting errors. fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(fmt, "{}", FormatReportFormatterBuilder::new(&self).build())?; + write!(fmt, "{}", FormatReportFormatterBuilder::new(self).build())?; Ok(()) } } diff --git a/src/lists.rs b/src/lists.rs index c04b478761693..d341ec8e6b0e7 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -386,7 +386,7 @@ where result.push('\n'); result.push_str(indent_str); // This is the width of the item (without comments). - line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(&s)); + line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(s)); } } else { result.push(' ') @@ -820,7 +820,7 @@ where pub(crate) fn total_item_width(item: &ListItem) -> usize { comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..])) + comment_len(item.post_comment.as_ref().map(|x| &(*x)[..])) - + item.item.as_ref().map_or(0, |s| unicode_str_width(&s)) + + item.item.as_ref().map_or(0, |s| unicode_str_width(s)) } fn comment_len(comment: Option<&str>) -> usize { diff --git a/src/macros.rs b/src/macros.rs index 927187dfd8a23..ef747638e33ec 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -186,7 +186,7 @@ fn return_macro_parse_failure_fallback( }) .unwrap_or(false); if is_like_block_indent_style { - return trim_left_preserve_layout(context.snippet(span), indent, &context.config); + return trim_left_preserve_layout(context.snippet(span), indent, context.config); } context.skipped_range.borrow_mut().push(( @@ -437,7 +437,7 @@ fn rewrite_macro_inner( // the `macro_name!` and `{ /* macro_body */ }` but skip modifying // anything in between the braces (for now). let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{'); - match trim_left_preserve_layout(snippet, shape.indent, &context.config) { + match trim_left_preserve_layout(snippet, shape.indent, context.config) { Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)), None => Some(format!("{} {}", macro_name, snippet)), } @@ -901,7 +901,7 @@ impl MacroArgParser { break; } TokenTree::Token(ref t) => { - buffer.push_str(&pprust::token_to_string(&t)); + buffer.push_str(&pprust::token_to_string(t)); } _ => return None, } @@ -1045,7 +1045,7 @@ fn wrap_macro_args_inner( let mut iter = args.iter().peekable(); let indent_str = shape.indent.to_string_with_newline(context.config); - while let Some(ref arg) = iter.next() { + while let Some(arg) = iter.next() { result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?); if use_multiple_lines @@ -1055,7 +1055,7 @@ fn wrap_macro_args_inner( result.pop(); } result.push_str(&indent_str); - } else if let Some(ref next_arg) = iter.peek() { + } else if let Some(next_arg) = iter.peek() { let space_before_dollar = !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar(); let space_before_brace = next_arg.kind.starts_with_brace(); @@ -1370,7 +1370,7 @@ impl MacroBranch { { s += &indent_str; } - (s + l + "\n", indent_next_line(kind, &l, &config)) + (s + l + "\n", indent_next_line(kind, l, &config)) }, ) .0; @@ -1514,11 +1514,11 @@ fn rewrite_macro_with_items( MacroArg::Item(item) => item, _ => return None, }; - visitor.visit_item(&item); + visitor.visit_item(item); } let mut result = String::with_capacity(256); - result.push_str(¯o_name); + result.push_str(macro_name); result.push_str(opener); result.push_str(&visitor.block_indent.to_string_with_newline(context.config)); result.push_str(visitor.buffer.trim()); diff --git a/src/matches.rs b/src/matches.rs index 5a6ed0ec06e55..22d23fc1cdba4 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -168,7 +168,7 @@ fn collect_beginning_verts( .map(|a| { context .snippet(a.pat.span) - .starts_with("|") + .starts_with('|') .then(|| a.pat.span().lo()) }) .collect() @@ -319,7 +319,7 @@ fn flatten_arm_body<'a>( let can_extend = |expr| !context.config.force_multiline_blocks() && can_flatten_block_around_this(expr); - if let Some(ref block) = block_can_be_flattened(context, body) { + if let Some(block) = block_can_be_flattened(context, body) { if let ast::StmtKind::Expr(ref expr) = block.stmts[0].kind { if let ast::ExprKind::Block(..) = expr.kind { flatten_arm_body(context, expr, None) @@ -393,7 +393,7 @@ fn rewrite_match_body( if comment_str.is_empty() { String::new() } else { - rewrite_comment(comment_str, false, shape, &context.config)? + rewrite_comment(comment_str, false, shape, context.config)? } }; @@ -408,8 +408,8 @@ fn rewrite_match_body( result.push_str(&arrow_comment); } result.push_str(&nested_indent_str); - result.push_str(&body_str); - result.push_str(&comma); + result.push_str(body_str); + result.push_str(comma); return Some(result); } @@ -451,7 +451,7 @@ fn rewrite_match_body( result.push_str(&arrow_comment); } result.push_str(&block_sep); - result.push_str(&body_str); + result.push_str(body_str); result.push_str(&body_suffix); Some(result) }; diff --git a/src/modules.rs b/src/modules.rs index ded34d9032f91..b1f229d9daaf5 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -16,7 +16,7 @@ use crate::syntux::parser::{ Directory, DirectoryOwnership, ModError, ModulePathSuccess, Parser, ParserError, }; use crate::syntux::session::ParseSess; -use crate::utils::contains_skip; +use crate::utils::{contains_skip, mk_sp}; mod visitor; @@ -135,10 +135,12 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { self.visit_mod_from_ast(&krate.items)?; } + let snippet_provider = self.parse_sess.snippet_provider(krate.span); + self.file_map.insert( root_filename, Module::new( - krate.span, + mk_sp(snippet_provider.start_pos(), snippet_provider.end_pos()), None, Cow::Borrowed(&krate.items), Cow::Borrowed(&krate.attrs), @@ -197,7 +199,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { /// Visit modules from AST. fn visit_mod_from_ast( &mut self, - items: &'ast Vec>, + items: &'ast [rustc_ast::ptr::P], ) -> Result<(), ModuleResolutionError> { for item in items { if is_cfg_if(item) { @@ -290,7 +292,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { }; self.visit_sub_mod_after_directory_update(sub_mod, Some(directory)) } - SubModKind::Internal(ref item) => { + SubModKind::Internal(item) => { self.push_inline_mod_directory(item.ident, &item.attrs); self.visit_sub_mod_after_directory_update(sub_mod, None) } @@ -317,9 +319,11 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> { } match (sub_mod.ast_mod_kind, sub_mod.items) { (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => { - self.visit_mod_from_ast(&items) + self.visit_mod_from_ast(items) + } + (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => { + self.visit_mod_outside_ast(items) } - (Some(Cow::Owned(..)), Cow::Owned(items)) => self.visit_mod_outside_ast(items), (_, _) => Ok(()), } } diff --git a/src/overflow.rs b/src/overflow.rs index ac24181c78052..3475f5c378cd2 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -394,7 +394,7 @@ impl<'a> Context<'a> { ) -> Option { let last_item = self.last_item()?; let rewrite = match last_item { - OverflowableItem::Expr(ref expr) => { + OverflowableItem::Expr(expr) => { match expr.kind { // When overflowing the closure which consists of a single control flow // expression, force to use block if its condition uses multi line. diff --git a/src/pairs.rs b/src/pairs.rs index 0f3d5e8f878ba..d1c75126ea4a7 100644 --- a/src/pairs.rs +++ b/src/pairs.rs @@ -55,11 +55,11 @@ fn rewrite_pairs_one_line( for ((_, rewrite), s) in list.list.iter().zip(list.separators.iter()) { if let Some(rewrite) = rewrite { - if !is_single_line(&rewrite) || result.len() > shape.width { + if !is_single_line(rewrite) || result.len() > shape.width { return None; } - result.push_str(&rewrite); + result.push_str(rewrite); result.push(' '); result.push_str(s); result.push(' '); @@ -94,18 +94,18 @@ fn rewrite_pairs_multiline( shape: Shape, context: &RewriteContext<'_>, ) -> Option { - let rhs_offset = shape.rhs_overhead(&context.config); + let rhs_offset = shape.rhs_overhead(context.config); let nested_shape = (match context.config.indent_style() { IndentStyle::Visual => shape.visual_indent(0), IndentStyle::Block => shape.block_indent(context.config.tab_spaces()), }) - .with_max_width(&context.config) + .with_max_width(context.config) .sub_width(rhs_offset)?; let indent_str = nested_shape.indent.to_string_with_newline(context.config); let mut result = String::new(); - result.push_str(&list.list[0].1.as_ref()?); + result.push_str(list.list[0].1.as_ref()?); for ((e, default_rw), s) in list.list[1..].iter().zip(list.separators.iter()) { // The following test checks if we should keep two subexprs on the same @@ -144,7 +144,7 @@ fn rewrite_pairs_multiline( } } - result.push_str(&default_rw.as_ref()?); + result.push_str(default_rw.as_ref()?); } Some(result) } @@ -264,12 +264,12 @@ impl FlattenPair for ast::Expr { return node.rewrite(context, shape); } let nested_overhead = sep + 1; - let rhs_offset = shape.rhs_overhead(&context.config); + let rhs_offset = shape.rhs_overhead(context.config); let nested_shape = (match context.config.indent_style() { IndentStyle::Visual => shape.visual_indent(0), IndentStyle::Block => shape.block_indent(context.config.tab_spaces()), }) - .with_max_width(&context.config) + .with_max_width(context.config) .sub_width(rhs_offset)?; let default_shape = match context.config.binop_separator() { SeparatorPlace::Back => nested_shape.sub_width(nested_overhead)?, diff --git a/src/patterns.rs b/src/patterns.rs index ba8d8024a9707..a80d63201f982 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -456,11 +456,11 @@ fn rewrite_tuple_pat( context: &RewriteContext<'_>, shape: Shape, ) -> Option { - let mut pat_vec: Vec<_> = pats.iter().map(|x| TuplePatField::Pat(x)).collect(); - - if pat_vec.is_empty() { + if pats.is_empty() { return Some(format!("{}()", path_str.unwrap_or_default())); } + let mut pat_vec: Vec<_> = pats.iter().map(TuplePatField::Pat).collect(); + let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape); let (pat_vec, span) = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2 { @@ -482,7 +482,7 @@ fn rewrite_tuple_pat( let path_str = path_str.unwrap_or_default(); overflow::rewrite_with_parens( - &context, + context, &path_str, pat_vec.iter(), shape, diff --git a/src/reorder.rs b/src/reorder.rs index 2c58350d4feb6..0732c8ee70059 100644 --- a/src/reorder.rs +++ b/src/reorder.rs @@ -118,7 +118,9 @@ fn rewrite_reorderable_or_regroupable_items( }; let mut regrouped_items = match context.config.group_imports() { - GroupImportsTactic::Preserve => vec![normalized_items], + GroupImportsTactic::Preserve | GroupImportsTactic::One => { + vec![normalized_items] + } GroupImportsTactic::StdExternalCrate => group_imports(normalized_items), }; diff --git a/src/syntux/parser.rs b/src/syntux/parser.rs index b5fe4335dd33d..d1bb2f80004aa 100644 --- a/src/syntux/parser.rs +++ b/src/syntux/parser.rs @@ -112,7 +112,7 @@ impl<'a> Parser<'a> { span: Span, ) -> Result<(Vec, Vec>, Span), ParserError> { let result = catch_unwind(AssertUnwindSafe(|| { - let mut parser = new_parser_from_file(sess.inner(), &path, Some(span)); + let mut parser = new_parser_from_file(sess.inner(), path, Some(span)); match parser.parse_mod(&TokenKind::Eof) { Ok(result) => Some(result), Err(mut e) => { @@ -125,18 +125,12 @@ impl<'a> Parser<'a> { } })); match result { - Ok(Some(m)) => { - if !sess.has_errors() { - return Ok(m); - } - - if sess.can_reset_errors() { - sess.reset_errors(); - return Ok(m); - } - Err(ParserError::ParseError) + Ok(Some(m)) if !sess.has_errors() => Ok(m), + Ok(Some(m)) if sess.can_reset_errors() => { + sess.reset_errors(); + Ok(m) } - Ok(None) => Err(ParserError::ParseError), + Ok(_) => Err(ParserError::ParseError), Err(..) if path.exists() => Err(ParserError::ParseError), Err(_) => Err(ParserError::ParsePanicError), } diff --git a/src/syntux/session.rs b/src/syntux/session.rs index 946c076d9f2d1..cdb4893d443b9 100644 --- a/src/syntux/session.rs +++ b/src/syntux/session.rs @@ -164,7 +164,7 @@ impl ParseSess { } pub(crate) fn ignore_file(&self, path: &FileName) -> bool { - self.ignore_path_set.as_ref().is_match(&path) + self.ignore_path_set.as_ref().is_match(path) } pub(crate) fn set_silent_emitter(&mut self) { diff --git a/src/test/mod.rs b/src/test/mod.rs index 48d61289a9b8f..e2620508c340b 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -535,9 +535,9 @@ fn check_files(files: Vec, opt_config: &Option) -> (Vec { - print!("{}", FormatReportFormatterBuilder::new(&report).build()); + print!("{}", FormatReportFormatterBuilder::new(report).build()); fails += 1; } Ok(report) => reports.push(report), diff --git a/src/test/mod_resolver.rs b/src/test/mod_resolver.rs index e0b55e3efb2c4..ae4a0d0fccb19 100644 --- a/src/test/mod_resolver.rs +++ b/src/test/mod_resolver.rs @@ -5,21 +5,39 @@ use super::read_config; use crate::{FileName, Input, Session}; -#[test] -fn nested_out_of_line_mods_loaded() { - // See also /~https://github.com/rust-lang/rustfmt/issues/4874 - let filename = "tests/mod-resolver/issue-4874/main.rs"; - let input_file = PathBuf::from(filename); +fn verify_mod_resolution(input_file_name: &str, exp_misformatted_files: &[&str]) { + let input_file = PathBuf::from(input_file_name); let config = read_config(&input_file); let mut session = Session::::new(config, None); let report = session - .format(Input::File(filename.into())) + .format(Input::File(input_file_name.into())) .expect("Should not have had any execution errors"); let errors_by_file = &report.internal.borrow().0; - assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from( - "tests/mod-resolver/issue-4874/bar/baz.rs", - )))); - assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from( - "tests/mod-resolver/issue-4874/foo/qux.rs", - )))); + for exp_file in exp_misformatted_files { + assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(exp_file)))); + } +} + +#[test] +fn nested_out_of_line_mods_loaded() { + // See also /~https://github.com/rust-lang/rustfmt/issues/4874 + verify_mod_resolution( + "tests/mod-resolver/issue-4874/main.rs", + &[ + "tests/mod-resolver/issue-4874/bar/baz.rs", + "tests/mod-resolver/issue-4874/foo/qux.rs", + ], + ); +} + +#[test] +fn out_of_line_nested_inline_within_out_of_line() { + // See also /~https://github.com/rust-lang/rustfmt/issues/5063 + verify_mod_resolution( + "tests/mod-resolver/issue-5063/main.rs", + &[ + "tests/mod-resolver/issue-5063/foo/bar/baz.rs", + "tests/mod-resolver/issue-5063/foo.rs", + ], + ); } diff --git a/src/types.rs b/src/types.rs index 62c05ba078c56..9ea90c5e46dd8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -728,7 +728,7 @@ impl Rewrite for ast::Ty { result = combine_strs_with_missing_comments( context, result.trim_end(), - &mt.ty.rewrite(&context, shape)?, + &mt.ty.rewrite(context, shape)?, before_ty_span, shape, true, @@ -738,7 +738,7 @@ impl Rewrite for ast::Ty { let budget = shape.width.checked_sub(used_width)?; let ty_str = mt .ty - .rewrite(&context, Shape::legacy(budget, shape.indent + used_width))?; + .rewrite(context, Shape::legacy(budget, shape.indent + used_width))?; result.push_str(&ty_str); } diff --git a/src/utils.rs b/src/utils.rs index 29e1e070d4111..3a8713c5bdb01 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -42,7 +42,7 @@ pub(crate) fn is_same_visibility(a: &Visibility, b: &Visibility) -> bool { ( VisibilityKind::Restricted { path: p, .. }, VisibilityKind::Restricted { path: q, .. }, - ) => pprust::path_to_string(&p) == pprust::path_to_string(&q), + ) => pprust::path_to_string(p) == pprust::path_to_string(q), (VisibilityKind::Public, VisibilityKind::Public) | (VisibilityKind::Inherited, VisibilityKind::Inherited) | ( @@ -689,7 +689,7 @@ mod test { #[test] fn test_remove_trailing_white_spaces() { let s = " r#\"\n test\n \"#"; - assert_eq!(remove_trailing_white_spaces(&s), s); + assert_eq!(remove_trailing_white_spaces(s), s); } #[test] @@ -698,7 +698,7 @@ mod test { let config = Config::default(); let indent = Indent::new(4, 0); assert_eq!( - trim_left_preserve_layout(&s, indent, &config), + trim_left_preserve_layout(s, indent, &config), Some("aaa\n bbb\n ccc".to_string()) ); } diff --git a/src/visitor.rs b/src/visitor.rs index 2cfd4e3f15c58..527042d098a1c 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -12,8 +12,7 @@ use crate::config::{BraceStyle, Config}; use crate::coverage::transform_missing_snippet; use crate::items::{ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate, - rewrite_impl_type, rewrite_opaque_type, rewrite_type, FnBraceStyle, FnSig, StaticParts, - StructParts, + rewrite_type_alias, FnBraceStyle, FnSig, ItemVisitorKind, StaticParts, StructParts, }; use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition}; use crate::modules::Module; @@ -164,7 +163,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ); } else { let shape = self.shape(); - let rewrite = self.with_context(|ctx| stmt.rewrite(&ctx, shape)); + let rewrite = self.with_context(|ctx| stmt.rewrite(ctx, shape)); self.push_rewrite(stmt.span(), rewrite) } } @@ -273,9 +272,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let comment_snippet = self.snippet(span); - let align_to_right = if unindent_comment && contains_comment(&comment_snippet) { + let align_to_right = if unindent_comment && contains_comment(comment_snippet) { let first_lines = comment_snippet.splitn(2, '/').next().unwrap_or(""); - last_line_width(first_lines) > last_line_width(&comment_snippet) + last_line_width(first_lines) > last_line_width(comment_snippet) } else { false }; @@ -439,7 +438,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let filtered_attrs; let mut attrs = &item.attrs; let skip_context_saved = self.skip_context.clone(); - self.skip_context.update_with_attrs(&attrs); + self.skip_context.update_with_attrs(attrs); let should_visit_node_again = match item.kind { // For use/extern crate items, skip rewriting attributes but check for a skip attribute. @@ -488,12 +487,12 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ast::ItemKind::Use(ref tree) => self.format_import(item, tree), ast::ItemKind::Impl { .. } => { let block_indent = self.block_indent; - let rw = self.with_context(|ctx| format_impl(&ctx, item, block_indent)); + let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent)); self.push_rewrite(item.span, rw); } ast::ItemKind::Trait(..) => { let block_indent = self.block_indent; - let rw = self.with_context(|ctx| format_trait(&ctx, item, block_indent)); + let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent)); self.push_rewrite(item.span, rw); } ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => { @@ -568,40 +567,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.push_rewrite(item.span, rewrite); } } - ast::ItemKind::TyAlias(ref alias_kind) => { - let ast::TyAlias { - ref generics, - ref bounds, - ref ty, - .. - } = **alias_kind; - match ty { - Some(ty) => { - let rewrite = rewrite_type( - &self.get_context(), - self.block_indent, - item.ident, - &item.vis, - generics, - Some(bounds), - Some(&*ty), - item.span, - ); - self.push_rewrite(item.span, rewrite); - } - None => { - let rewrite = rewrite_opaque_type( - &self.get_context(), - self.block_indent, - item.ident, - bounds, - generics, - &item.vis, - item.span, - ); - self.push_rewrite(item.span, rewrite); - } - } + ast::ItemKind::TyAlias(ref ty_alias) => { + use ItemVisitorKind::Item; + self.visit_ty_alias_kind(ty_alias, &Item(&item), item.span); } ast::ItemKind::GlobalAsm(..) => { let snippet = Some(self.snippet(item.span).to_owned()); @@ -624,18 +592,46 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.skip_context = skip_context_saved; } - pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) { - skip_out_of_file_lines_range_visitor!(self, ti.span); + fn visit_ty_alias_kind( + &mut self, + ty_kind: &ast::TyAlias, + visitor_kind: &ItemVisitorKind<'_>, + span: Span, + ) { + let rewrite = rewrite_type_alias( + ty_kind, + &self.get_context(), + self.block_indent, + visitor_kind, + span, + ); + self.push_rewrite(span, rewrite); + } + + fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) { + use ItemVisitorKind::*; + // TODO(calebcartwright): Not sure the skip spans are correct + let (ai, skip_span, assoc_ctxt) = match visitor_kind { + AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait), + AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl), + _ => unreachable!(), + }; + skip_out_of_file_lines_range_visitor!(self, ai.span); - if self.visit_attrs(&ti.attrs, ast::AttrStyle::Outer) { - self.push_skipped_with_span(ti.attrs.as_slice(), ti.span(), ti.span()); + if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) { + self.push_skipped_with_span(&ai.attrs.as_slice(), skip_span, skip_span); return; } // TODO(calebcartwright): consider enabling box_patterns feature gate - match ti.kind { - ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_trait_item(ti)), - ast::AssocItemKind::Fn(ref fn_kind) => { + match (&ai.kind, visitor_kind) { + (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => { + self.visit_static(&StaticParts::from_trait_item(&ai)) + } + (ast::AssocItemKind::Const(..), AssocImplItem(_)) => { + self.visit_static(&StaticParts::from_impl_item(&ai)) + } + (ast::AssocItemKind::Fn(ref fn_kind), _) => { let ast::Fn { defaultness, ref sig, @@ -643,108 +639,39 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ref body, } = **fn_kind; if let Some(ref body) = body { - let inner_attrs = inner_attributes(&ti.attrs); - let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait); + let inner_attrs = inner_attributes(&ai.attrs); + let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt); self.visit_fn( - visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &ti.vis, Some(body)), + visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)), generics, &sig.decl, - ti.span, + ai.span, defaultness, Some(&inner_attrs), ); } else { let indent = self.block_indent; let rewrite = - self.rewrite_required_fn(indent, ti.ident, sig, &ti.vis, generics, ti.span); - self.push_rewrite(ti.span, rewrite); + self.rewrite_required_fn(indent, ai.ident, sig, &ai.vis, generics, ai.span); + self.push_rewrite(ai.span, rewrite); } } - ast::AssocItemKind::TyAlias(ref ty_alias_kind) => { - let ast::TyAlias { - ref generics, - ref bounds, - ref ty, - .. - } = **ty_alias_kind; - let rewrite = rewrite_type( - &self.get_context(), - self.block_indent, - ti.ident, - &ti.vis, - generics, - Some(bounds), - ty.as_ref(), - ti.span, - ); - self.push_rewrite(ti.span, rewrite); + (ast::AssocItemKind::TyAlias(ref ty_alias), _) => { + self.visit_ty_alias_kind(ty_alias, visitor_kind, ai.span); } - ast::AssocItemKind::MacCall(ref mac) => { - self.visit_mac(mac, Some(ti.ident), MacroPosition::Item); + (ast::AssocItemKind::MacCall(ref mac), _) => { + self.visit_mac(mac, Some(ai.ident), MacroPosition::Item); } + _ => unreachable!(), } } - pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) { - skip_out_of_file_lines_range_visitor!(self, ii.span); - - if self.visit_attrs(&ii.attrs, ast::AttrStyle::Outer) { - self.push_skipped_with_span(ii.attrs.as_slice(), ii.span, ii.span); - return; - } + pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) { + self.visit_assoc_item(&ItemVisitorKind::AssocTraitItem(ti)); + } - match ii.kind { - ast::AssocItemKind::Fn(ref fn_kind) => { - let ast::Fn { - defaultness, - ref sig, - ref generics, - ref body, - } = **fn_kind; - if let Some(ref body) = body { - let inner_attrs = inner_attributes(&ii.attrs); - let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Impl); - self.visit_fn( - visit::FnKind::Fn(fn_ctxt, ii.ident, sig, &ii.vis, Some(body)), - generics, - &sig.decl, - ii.span, - defaultness, - Some(&inner_attrs), - ); - } else { - let indent = self.block_indent; - let rewrite = - self.rewrite_required_fn(indent, ii.ident, sig, &ii.vis, generics, ii.span); - self.push_rewrite(ii.span, rewrite); - } - } - ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)), - ast::AssocItemKind::TyAlias(ref ty_alias_kind) => { - let ast::TyAlias { - defaultness, - ref generics, - ref ty, - .. - } = **ty_alias_kind; - self.push_rewrite( - ii.span, - rewrite_impl_type( - ii.ident, - &ii.vis, - defaultness, - ty.as_ref(), - &generics, - &self.get_context(), - self.block_indent, - ii.span, - ), - ); - } - ast::AssocItemKind::MacCall(ref mac) => { - self.visit_mac(mac, Some(ii.ident), MacroPosition::Item); - } - } + pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) { + self.visit_assoc_item(&ItemVisitorKind::AssocImplItem(ii)); } fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option, pos: MacroPosition) { @@ -921,7 +848,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } fn walk_mod_items(&mut self, items: &[rustc_ast::ptr::P]) { - self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&items)); + self.visit_items_with_reordering(&ptr_vec_to_ref_vec(items)); } fn walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool) { diff --git a/tests/mod-resolver/issue-5063/foo.rs b/tests/mod-resolver/issue-5063/foo.rs new file mode 100644 index 0000000000000..d56974773fb9f --- /dev/null +++ b/tests/mod-resolver/issue-5063/foo.rs @@ -0,0 +1,2 @@ +mod bar { + mod baz;} \ No newline at end of file diff --git a/tests/mod-resolver/issue-5063/foo/bar/baz.rs b/tests/mod-resolver/issue-5063/foo/bar/baz.rs new file mode 100644 index 0000000000000..3519b0ee59c88 --- /dev/null +++ b/tests/mod-resolver/issue-5063/foo/bar/baz.rs @@ -0,0 +1 @@ +fn baz() { } \ No newline at end of file diff --git a/tests/mod-resolver/issue-5063/main.rs b/tests/mod-resolver/issue-5063/main.rs new file mode 100644 index 0000000000000..41c81c7bb433c --- /dev/null +++ b/tests/mod-resolver/issue-5063/main.rs @@ -0,0 +1,5 @@ +fn main() { + println!("Hello, world!"); +} + +mod foo; \ No newline at end of file diff --git a/tests/source/configs/group_imports/One-merge_imports.rs b/tests/source/configs/group_imports/One-merge_imports.rs new file mode 100644 index 0000000000000..157d3857908a4 --- /dev/null +++ b/tests/source/configs/group_imports/One-merge_imports.rs @@ -0,0 +1,17 @@ +// rustfmt-group_imports: One +// rustfmt-imports_granularity: Crate +use chrono::Utc; +use super::update::convert_publish_payload; + +use juniper::{FieldError, FieldResult}; +use uuid::Uuid; +use alloc::alloc::Layout; + +use std::sync::Arc; +use alloc::vec::Vec; + +use broker::database::PooledConnection; + +use super::schema::{Context, Payload}; +use core::f32; +use crate::models::Event; diff --git a/tests/source/configs/group_imports/One-nested.rs b/tests/source/configs/group_imports/One-nested.rs new file mode 100644 index 0000000000000..109bd07e1ee29 --- /dev/null +++ b/tests/source/configs/group_imports/One-nested.rs @@ -0,0 +1,7 @@ +// rustfmt-group_imports: One +mod test { + use crate::foo::bar; + + use std::path; + use crate::foo::bar2; +} diff --git a/tests/source/configs/group_imports/One-no_reorder.rs b/tests/source/configs/group_imports/One-no_reorder.rs new file mode 100644 index 0000000000000..f82f62c7f5b2c --- /dev/null +++ b/tests/source/configs/group_imports/One-no_reorder.rs @@ -0,0 +1,16 @@ +// rustfmt-group_imports: One +// rustfmt-reorder_imports: false +use chrono::Utc; +use super::update::convert_publish_payload; + +use juniper::{FieldError, FieldResult}; +use uuid::Uuid; +use alloc::alloc::Layout; + +use std::sync::Arc; + +use broker::database::PooledConnection; + +use super::schema::{Context, Payload}; +use core::f32; +use crate::models::Event; diff --git a/tests/source/configs/group_imports/One.rs b/tests/source/configs/group_imports/One.rs new file mode 100644 index 0000000000000..5ab7a950805b1 --- /dev/null +++ b/tests/source/configs/group_imports/One.rs @@ -0,0 +1,15 @@ +// rustfmt-group_imports: One +use chrono::Utc; +use super::update::convert_publish_payload; + +use juniper::{FieldError, FieldResult}; +use uuid::Uuid; +use alloc::alloc::Layout; + +use std::sync::Arc; + +use broker::database::PooledConnection; + +use super::schema::{Context, Payload}; +use core::f32; +use crate::models::Event; diff --git a/tests/source/empty-item-single-line-false.rs b/tests/source/empty-item-single-line-false.rs new file mode 100644 index 0000000000000..20c5bc83b466a --- /dev/null +++ b/tests/source/empty-item-single-line-false.rs @@ -0,0 +1,46 @@ +// rustfmt-brace_style: AlwaysNextLine +// rustfmt-empty_item_single_line: false + +fn function() +{ + +} + +struct Struct +{ + +} + +enum Enum +{ + +} + +trait Trait +{ + +} + +impl Trait for T +{ + +} + +trait Trait2 +where + T: Copy + Display + Write + Read + FromStr, {} + +trait Trait3 +where + T: Something + + SomethingElse + + Sync + + Send + + Display + + Debug + + Copy + + Hash + + Debug + + Display + + Write + + Read, {} diff --git a/tests/source/item-brace-style-always-next-line.rs b/tests/source/item-brace-style-always-next-line.rs index 38094d67a7737..0fb6405120aa7 100644 --- a/tests/source/item-brace-style-always-next-line.rs +++ b/tests/source/item-brace-style-always-next-line.rs @@ -27,3 +27,38 @@ mod M { struct D where T: Copy {} } + + +fn function() +{ + +} + +trait Trait +{ + +} + +impl Trait for T +{ + +} + +trait Trait2 +where + T: Copy + Display + Write + Read + FromStr, {} + +trait Trait3 +where + T: Something + + SomethingElse + + Sync + + Send + + Display + + Debug + + Copy + + Hash + + Debug + + Display + + Write + + Read, {} diff --git a/tests/target/configs/group_imports/One-merge_imports.rs b/tests/target/configs/group_imports/One-merge_imports.rs new file mode 100644 index 0000000000000..52e0e1c5ac215 --- /dev/null +++ b/tests/target/configs/group_imports/One-merge_imports.rs @@ -0,0 +1,14 @@ +// rustfmt-group_imports: One +// rustfmt-imports_granularity: Crate +use super::{ + schema::{Context, Payload}, + update::convert_publish_payload, +}; +use crate::models::Event; +use alloc::{alloc::Layout, vec::Vec}; +use broker::database::PooledConnection; +use chrono::Utc; +use core::f32; +use juniper::{FieldError, FieldResult}; +use std::sync::Arc; +use uuid::Uuid; diff --git a/tests/target/configs/group_imports/One-nested.rs b/tests/target/configs/group_imports/One-nested.rs new file mode 100644 index 0000000000000..5b648548260f8 --- /dev/null +++ b/tests/target/configs/group_imports/One-nested.rs @@ -0,0 +1,6 @@ +// rustfmt-group_imports: One +mod test { + use crate::foo::bar; + use crate::foo::bar2; + use std::path; +} diff --git a/tests/target/configs/group_imports/One-no_reorder.rs b/tests/target/configs/group_imports/One-no_reorder.rs new file mode 100644 index 0000000000000..015e841d01486 --- /dev/null +++ b/tests/target/configs/group_imports/One-no_reorder.rs @@ -0,0 +1,12 @@ +// rustfmt-group_imports: One +// rustfmt-reorder_imports: false +use chrono::Utc; +use super::update::convert_publish_payload; +use juniper::{FieldError, FieldResult}; +use uuid::Uuid; +use alloc::alloc::Layout; +use std::sync::Arc; +use broker::database::PooledConnection; +use super::schema::{Context, Payload}; +use core::f32; +use crate::models::Event; diff --git a/tests/target/configs/group_imports/One.rs b/tests/target/configs/group_imports/One.rs new file mode 100644 index 0000000000000..3094c7ae11572 --- /dev/null +++ b/tests/target/configs/group_imports/One.rs @@ -0,0 +1,11 @@ +// rustfmt-group_imports: One +use super::schema::{Context, Payload}; +use super::update::convert_publish_payload; +use crate::models::Event; +use alloc::alloc::Layout; +use broker::database::PooledConnection; +use chrono::Utc; +use core::f32; +use juniper::{FieldError, FieldResult}; +use std::sync::Arc; +use uuid::Uuid; diff --git a/tests/target/empty-item-single-line-false.rs b/tests/target/empty-item-single-line-false.rs new file mode 100644 index 0000000000000..bf7f70e7c4321 --- /dev/null +++ b/tests/target/empty-item-single-line-false.rs @@ -0,0 +1,41 @@ +// rustfmt-brace_style: AlwaysNextLine +// rustfmt-empty_item_single_line: false + +fn function() +{ +} + +struct Struct {} + +enum Enum {} + +trait Trait +{ +} + +impl Trait for T +{ +} + +trait Trait2 +where + T: Copy + Display + Write + Read + FromStr, +{ +} + +trait Trait3 +where + T: Something + + SomethingElse + + Sync + + Send + + Display + + Debug + + Copy + + Hash + + Debug + + Display + + Write + + Read, +{ +} diff --git a/tests/target/issue-5012/trailing_comma_always.rs b/tests/target/issue-5012/trailing_comma_always.rs new file mode 100644 index 0000000000000..ff9c40fbbd8d2 --- /dev/null +++ b/tests/target/issue-5012/trailing_comma_always.rs @@ -0,0 +1,8 @@ +// rustfmt-trailing_comma: Always + +pub struct Matrix +where + [T; R * C]:, +{ + contents: [T; R * C], +} diff --git a/tests/target/issue-5012/trailing_comma_never.rs b/tests/target/issue-5012/trailing_comma_never.rs new file mode 100644 index 0000000000000..2fac8eae52b86 --- /dev/null +++ b/tests/target/issue-5012/trailing_comma_never.rs @@ -0,0 +1,8 @@ +// rustfmt-trailing_comma: Never + +pub struct Matrix +where + [T; R * C]: +{ + contents: [T; R * C] +} diff --git a/tests/target/issue-5033/minimum_example.rs b/tests/target/issue-5033/minimum_example.rs new file mode 100644 index 0000000000000..0e7df41deb2d9 --- /dev/null +++ b/tests/target/issue-5033/minimum_example.rs @@ -0,0 +1,8 @@ +// leading comment + +#![rustfmt::skip] +fn main() { + println!("main"); // commented +} + +// post comment diff --git a/tests/target/issue-5033/nested_modules.rs b/tests/target/issue-5033/nested_modules.rs new file mode 100644 index 0000000000000..7a11133b60bb1 --- /dev/null +++ b/tests/target/issue-5033/nested_modules.rs @@ -0,0 +1,11 @@ +#![rustfmt::skip] + +mod a { + mod b { + + } + + // trailing comment b +} + +// trailing comment a diff --git a/tests/target/issue_4850.rs b/tests/target/issue_4850.rs new file mode 100644 index 0000000000000..7d4da9022fe4b --- /dev/null +++ b/tests/target/issue_4850.rs @@ -0,0 +1,4 @@ +impl ThisIsALongStructNameToPushTheWhereToWrapLolololol where + [(); this_is_a_long_const_function_name()]: +{ +} diff --git a/tests/target/item-brace-style-always-next-line.rs b/tests/target/item-brace-style-always-next-line.rs index 531ac59868314..4935fac04f111 100644 --- a/tests/target/item-brace-style-always-next-line.rs +++ b/tests/target/item-brace-style-always-next-line.rs @@ -40,3 +40,32 @@ mod M where T: Copy, {} } + +fn function() {} + +trait Trait {} + +impl Trait for T {} + +trait Trait2 +where + T: Copy + Display + Write + Read + FromStr, +{ +} + +trait Trait3 +where + T: Something + + SomethingElse + + Sync + + Send + + Display + + Debug + + Copy + + Hash + + Debug + + Display + + Write + + Read, +{ +} From e6d1bf5acba29a8944f3bd537bcefb5e5972e5f1 Mon Sep 17 00:00:00 2001 From: Wu Yu Wei Date: Tue, 31 Mar 2020 14:36:12 +0800 Subject: [PATCH 02/16] Link tracking issues in Configurations.md (#4096) # Conflicts: # Configurations.md --- Configurations.md | 94 +++++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Configurations.md b/Configurations.md index 13826883d2f4b..4a281251f2275 100644 --- a/Configurations.md +++ b/Configurations.md @@ -47,7 +47,7 @@ Where to put a binary operator when a binary expression goes multiline. - **Default value**: `"Front"` - **Possible values**: `"Front"`, `"Back"` -- **Stable**: No (tracking issue: #3368) +- **Stable**: No (tracking issue: [#3368](/~https://github.com/rust-lang/rustfmt/issues/3368)) #### `"Front"` (default): @@ -88,7 +88,7 @@ them, additional blank lines are inserted. - **Default value**: `0` - **Possible values**: *unsigned integer* -- **Stable**: No (tracking issue: #3382) +- **Stable**: No (tracking issue: [#3382](/~https://github.com/rust-lang/rustfmt/issues/3382)) ### Example Original Code (rustfmt will not change it with the default value of `0`): @@ -128,7 +128,7 @@ lines are found, they are trimmed down to match this integer. - **Default value**: `1` - **Possible values**: any non-negative integer -- **Stable**: No (tracking issue: #3381) +- **Stable**: No (tracking issue: [#3381](/~https://github.com/rust-lang/rustfmt/issues/3381)) ### Example Original Code: @@ -186,7 +186,7 @@ Brace style for items - **Default value**: `"SameLineWhere"` - **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"` -- **Stable**: No (tracking issue: #3376) +- **Stable**: No (tracking issue: [#3376](/~https://github.com/rust-lang/rustfmt/issues/3376)) ### Functions @@ -313,7 +313,7 @@ Whether to use colored output or not. - **Default value**: `"Auto"` - **Possible values**: "Auto", "Always", "Never" -- **Stable**: No (tracking issue: #3385) +- **Stable**: No (tracking issue: [#3385](/~https://github.com/rust-lang/rustfmt/issues/3385)) ## `combine_control_expr` @@ -321,7 +321,7 @@ Combine control expressions with function calls. - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3369) +- **Stable**: No (tracking issue: [#3369](/~https://github.com/rust-lang/rustfmt/issues/3369)) #### `true` (default): @@ -429,7 +429,7 @@ Maximum length of comments. No effect unless`wrap_comments = true`. - **Default value**: `80` - **Possible values**: any positive integer -- **Stable**: No (tracking issue: #3349) +- **Stable**: No (tracking issue: [#3349](/~https://github.com/rust-lang/rustfmt/issues/3349)) **Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width. @@ -452,7 +452,7 @@ Replace strings of _ wildcards by a single .. in tuple patterns - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3384) +- **Stable**: No (tracking issue: [#3384](/~https://github.com/rust-lang/rustfmt/issues/3384)) #### `false` (default): @@ -477,7 +477,7 @@ Brace style for control flow constructs - **Default value**: `"AlwaysSameLine"` - **Possible values**: `"AlwaysNextLine"`, `"AlwaysSameLine"`, `"ClosingNextLine"` -- **Stable**: No (tracking issue: #3377) +- **Stable**: No (tracking issue: [#3377](/~https://github.com/rust-lang/rustfmt/issues/3377)) #### `"AlwaysSameLine"` (default): @@ -551,7 +551,7 @@ Put empty-body functions and impls on a single line - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3356) +- **Stable**: No (tracking issue: [#3356](/~https://github.com/rust-lang/rustfmt/issues/3356)) #### `true` (default): @@ -584,7 +584,7 @@ doesn't get ignored when aligning. - **Default value** : 0 - **Possible values**: any positive integer -- **Stable**: No (tracking issue: #3372) +- **Stable**: No (tracking issue: [#3372](/~https://github.com/rust-lang/rustfmt/issues/3372)) #### `0` (default): @@ -630,7 +630,7 @@ using a shorter name. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3391) +- **Stable**: No (tracking issue: [#3391](/~https://github.com/rust-lang/rustfmt/issues/3391)) See also [`max_width`](#max_width). @@ -641,7 +641,7 @@ trailing whitespaces. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3392) +- **Stable**: No (tracking issue: [#3392](/~https://github.com/rust-lang/rustfmt/issues/3392)) ## `fn_args_layout` @@ -771,7 +771,7 @@ Put single-expression functions on a single line - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3358) +- **Stable**: No (tracking issue: [#3358](/~https://github.com/rust-lang/rustfmt/issues/3358)) #### `false` (default): @@ -832,7 +832,7 @@ Force multiline closure and match arm bodies to be wrapped in a block - **Default value**: `false` - **Possible values**: `false`, `true` -- **Stable**: No (tracking issue: #3374) +- **Stable**: No (tracking issue: [#3374](/~https://github.com/rust-lang/rustfmt/issues/3374)) #### `false` (default): @@ -881,7 +881,7 @@ Format code snippet included in doc comments. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3348) +- **Stable**: No (tracking issue: [#3348](/~https://github.com/rust-lang/rustfmt/issues/3348)) #### `false` (default): @@ -941,7 +941,7 @@ Format the metavariable matching patterns in macros. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3354) +- **Stable**: No (tracking issue: [#3354](/~https://github.com/rust-lang/rustfmt/issues/3354)) #### `false` (default): @@ -978,7 +978,7 @@ Format the bodies of macros. - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3355) +- **Stable**: No (tracking issue: [#3355](/~https://github.com/rust-lang/rustfmt/issues/3355)) #### `true` (default): @@ -1011,7 +1011,7 @@ Format string literals where necessary - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3353) +- **Stable**: No (tracking issue: [#3353](/~https://github.com/rust-lang/rustfmt/issues/3353)) #### `false` (default): @@ -1072,7 +1072,7 @@ Do not show parse errors if the parser failed to parse files. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3390) +- **Stable**: No (tracking issue: [#3390](/~https://github.com/rust-lang/rustfmt/issues/3390)) ## `ignore` @@ -1081,7 +1081,7 @@ The pattern format is the same as [.gitignore](https://git-scm.com/docs/gitignor - **Default value**: format every file - **Possible values**: See an example below -- **Stable**: No (tracking issue: #3395) +- **Stable**: No (tracking issue: [#3395](/~https://github.com/rust-lang/rustfmt/issues/3395)) ### Example @@ -1114,7 +1114,7 @@ Indent style of imports - **Default Value**: `"Block"` - **Possible values**: `"Block"`, `"Visual"` -- **Stable**: No (tracking issue: #3360) +- **Stable**: No (tracking issue: [#3360](/~https://github.com/rust-lang/rustfmt/issues/3360)) #### `"Block"` (default): @@ -1140,7 +1140,7 @@ Item layout inside a imports block - **Default value**: "Mixed" - **Possible values**: "Horizontal", "HorizontalVertical", "Mixed", "Vertical" -- **Stable**: No (tracking issue: #3361) +- **Stable**: No (tracking issue: [#3361](/~https://github.com/rust-lang/rustfmt/issues/3361)) #### `"Mixed"` (default): @@ -1203,7 +1203,7 @@ Indent on expressions or items. - **Default value**: `"Block"` - **Possible values**: `"Block"`, `"Visual"` -- **Stable**: No (tracking issue: #3346) +- **Stable**: No (tracking issue: [#3346](/~https://github.com/rust-lang/rustfmt/issues/3346)) ### Array @@ -1456,7 +1456,7 @@ Write an item and its attribute on the same line if their combined width is belo - **Default value**: 0 - **Possible values**: any positive integer -- **Stable**: No (tracking issue: #3343) +- **Stable**: No (tracking issue: [#3343](/~https://github.com/rust-lang/rustfmt/issues/3343)) ### Example @@ -1477,7 +1477,7 @@ Check whether beginnings of files match a license template. - **Default value**: `""` - **Possible values**: path to a license template file -- **Stable**: No (tracking issue: #3352) +- **Stable**: No (tracking issue: [#3352](/~https://github.com/rust-lang/rustfmt/issues/3352)) A license template is a plain text file which is matched literally against the beginning of each source file, except for `{}`-delimited blocks, which are @@ -1499,7 +1499,7 @@ The Style Guide requires that bodies are block wrapped by default if a line brea - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3373) +- **Stable**: No (tracking issue: [#3373](/~https://github.com/rust-lang/rustfmt/issues/3373)) #### `true` (default): @@ -1826,7 +1826,7 @@ Convert /* */ comments to // comments where possible - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3350) +- **Stable**: No (tracking issue: [#3350](/~https://github.com/rust-lang/rustfmt/issues/3350)) #### `false` (default): @@ -1854,7 +1854,7 @@ Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3351) +- **Stable**: No (tracking issue: [#3351](/~https://github.com/rust-lang/rustfmt/issues/3351)) #### `false` (default): @@ -1885,7 +1885,7 @@ instead of being indented on a new line. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3370) +- **Stable**: No (tracking issue: [#3370](/~https://github.com/rust-lang/rustfmt/issues/3370)) #### `false` (default): @@ -1992,7 +1992,7 @@ Reorder impl items. `type` and `const` are put first, then macros and methods. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3363) +- **Stable**: No (tracking issue: [#3363](/~https://github.com/rust-lang/rustfmt/issues/3363)) #### `false` (default) @@ -2166,7 +2166,7 @@ Report `FIXME` items in comments. - **Default value**: `"Never"` - **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"` -- **Stable**: No (tracking issue: #3394) +- **Stable**: No (tracking issue: [#3394](/~https://github.com/rust-lang/rustfmt/issues/3394)) Warns about any comments containing `FIXME` in them when set to `"Always"`. If it contains a `#X` (with `X` being a number) in parentheses following the @@ -2181,7 +2181,7 @@ Report `TODO` items in comments. - **Default value**: `"Never"` - **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"` -- **Stable**: No (tracking issue: #3393) +- **Stable**: No (tracking issue: [#3393](/~https://github.com/rust-lang/rustfmt/issues/3393)) Warns about any comments containing `TODO` in them when set to `"Always"`. If it contains a `#X` (with `X` being a number) in parentheses following the @@ -2196,7 +2196,7 @@ specific version of rustfmt is used in your CI, use this option. - **Default value**: `CARGO_PKG_VERSION` - **Possible values**: any published version (e.g. `"0.3.8"`) -- **Stable**: No (tracking issue: #3386) +- **Stable**: No (tracking issue: [#3386](/~https://github.com/rust-lang/rustfmt/issues/3386)) ## `skip_children` @@ -2204,7 +2204,7 @@ Don't reformat out of line modules - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3389) +- **Stable**: No (tracking issue: [#3389](/~https://github.com/rust-lang/rustfmt/issues/3386)) ## `single_line_if_else_max_width` @@ -2224,7 +2224,7 @@ Leave a space after the colon. - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3366) +- **Stable**: No (tracking issue: [#3366](/~https://github.com/rust-lang/rustfmt/issues/3366)) #### `true` (default): @@ -2256,7 +2256,7 @@ Leave a space before the colon. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3365) +- **Stable**: No (tracking issue: [#3365](/~https://github.com/rust-lang/rustfmt/issues/3365)) #### `false` (default): @@ -2288,7 +2288,7 @@ Put spaces around the .., ..=, and ... range operators - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3367) +- **Stable**: No (tracking issue: [#3367](/~https://github.com/rust-lang/rustfmt/issues/3367)) #### `false` (default): @@ -2344,7 +2344,7 @@ The maximum diff of width between struct fields to be aligned with each other. - **Default value** : 0 - **Possible values**: any non-negative integer -- **Stable**: No (tracking issue: #3371) +- **Stable**: No (tracking issue: [#3371](/~https://github.com/rust-lang/rustfmt/issues/3371)) #### `0` (default): @@ -2372,7 +2372,7 @@ Put small struct literals on a single line - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3357) +- **Stable**: No (tracking issue: [#3357](/~https://github.com/rust-lang/rustfmt/issues/3357)) #### `true` (default): @@ -2460,7 +2460,7 @@ How to handle trailing commas for lists - **Default value**: `"Vertical"` - **Possible values**: `"Always"`, `"Never"`, `"Vertical"` -- **Stable**: No (tracking issue: #3379) +- **Stable**: No (tracking issue: [#3379](/~https://github.com/rust-lang/rustfmt/issues/3379)) #### `"Vertical"` (default): @@ -2518,7 +2518,7 @@ Add trailing semicolon after break, continue and return - **Default value**: `true` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3378) +- **Stable**: No (tracking issue: [#3378](/~https://github.com/rust-lang/rustfmt/issues/3378)) #### `true` (default): ```rust @@ -2540,7 +2540,7 @@ Determines if `+` or `=` are wrapped in spaces in the punctuation of types - **Default value**: `"Wide"` - **Possible values**: `"Compressed"`, `"Wide"` -- **Stable**: No (tracking issue: #3364) +- **Stable**: No (tracking issue: [#3364](/~https://github.com/rust-lang/rustfmt/issues/3364)) #### `"Wide"` (default): @@ -2564,7 +2564,7 @@ Enable unstable features on the unstable channel. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3387) +- **Stable**: No (tracking issue: [#3387](/~https://github.com/rust-lang/rustfmt/issues/3387)) ## `use_field_init_shorthand` @@ -2779,7 +2779,7 @@ version number. - **Default value**: `One` - **Possible values**: `One`, `Two` -- **Stable**: No (tracking issue: #3383) +- **Stable**: No (tracking issue: [#3383](/~https://github.com/rust-lang/rustfmt/issues/3383)) ### Example @@ -2793,7 +2793,7 @@ Forces the `where` clause to be laid out on a single line. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3359) +- **Stable**: No (tracking issue: [#3359](/~https://github.com/rust-lang/rustfmt/issues/3359)) #### `false` (default): @@ -2825,7 +2825,7 @@ Break comments to fit on the line - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No (tracking issue: #3347) +- **Stable**: No (tracking issue: [#3347](/~https://github.com/rust-lang/rustfmt/issues/3347)) #### `false` (default): From eee8f0419dca910187350ac38fe9694b8b7919b9 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Wed, 17 Nov 2021 12:51:37 -0600 Subject: [PATCH 03/16] refactor: cleanup duplicative Impl handling code --- src/items.rs | 453 +++++++++++++++++++++++-------------------------- src/visitor.rs | 4 +- 2 files changed, 212 insertions(+), 245 deletions(-) diff --git a/src/items.rs b/src/items.rs index 50121a8b6b50e..849e6c06218f8 100644 --- a/src/items.rs +++ b/src/items.rs @@ -579,6 +579,25 @@ impl<'a> FmtVisitor<'a> { fn visit_impl_items(&mut self, items: &[ptr::P]) { if self.get_context().config.reorder_impl_items() { + type TyOpt = Option>; + use crate::ast::AssocItemKind::*; + let is_type = |ty: &TyOpt| { + ty.as_ref() + .map_or(true, |t| !matches!(t.kind, ast::TyKind::ImplTrait(..))) + }; + let is_opaque = |ty: &TyOpt| !is_type(ty); + let both_type = |left: &TyOpt, right: &TyOpt| is_type(left) && is_type(right); + let both_opaque = |left: &TyOpt, right: &TyOpt| is_opaque(left) && is_opaque(right); + let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) { + (TyAlias(lty), TyAlias(rty)) + if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) => + { + false + } + (Const(..), Const(..)) => false, + _ => true, + }; + // Create visitor for each items, then reorder them. let mut buffer = vec![]; for item in items { @@ -587,50 +606,6 @@ impl<'a> FmtVisitor<'a> { self.buffer.clear(); } - fn is_type(ty: &Option>) -> bool { - if let Some(lty) = ty { - if let ast::TyKind::ImplTrait(..) = lty.kind { - return false; - } - } - true - } - - fn is_opaque(ty: &Option>) -> bool { - !is_type(ty) - } - - fn both_type( - a: &Option>, - b: &Option>, - ) -> bool { - is_type(a) && is_type(b) - } - - fn both_opaque( - a: &Option>, - b: &Option>, - ) -> bool { - is_opaque(a) && is_opaque(b) - } - - // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but - // we still need to differentiate to maintain sorting order. - - // type -> opaque -> const -> macro -> method - use crate::ast::AssocItemKind::*; - fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool { - match (a, b) { - (TyAlias(lty), TyAlias(rty)) - if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) => - { - false - } - (Const(..), Const(..)) => false, - _ => true, - } - } - buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) { (TyAlias(lty), TyAlias(rty)) if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) => @@ -676,136 +651,133 @@ impl<'a> FmtVisitor<'a> { pub(crate) fn format_impl( context: &RewriteContext<'_>, item: &ast::Item, + iimpl: &ast::Impl, offset: Indent, ) -> Option { - if let ast::ItemKind::Impl(impl_kind) = &item.kind { - let ast::Impl { - ref generics, - ref self_ty, - ref items, - .. - } = **impl_kind; - let mut result = String::with_capacity(128); - let ref_and_type = format_impl_ref_and_type(context, item, offset)?; - let sep = offset.to_string_with_newline(context.config); - result.push_str(&ref_and_type); + let ast::Impl { + generics, + self_ty, + items, + .. + } = iimpl; + let mut result = String::with_capacity(128); + let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?; + let sep = offset.to_string_with_newline(context.config); + result.push_str(&ref_and_type); - let where_budget = if result.contains('\n') { - context.config.max_width() - } else { - context.budget(last_line_width(&result)) - }; + let where_budget = if result.contains('\n') { + context.config.max_width() + } else { + context.budget(last_line_width(&result)) + }; - let mut option = WhereClauseOption::snuggled(&ref_and_type); - let snippet = context.snippet(item.span); - let open_pos = snippet.find_uncommented("{")? + 1; - if !contains_comment(&snippet[open_pos..]) - && items.is_empty() - && generics.where_clause.predicates.len() == 1 - && !result.contains('\n') - { - option.suppress_comma(); - option.snuggle(); - option.allow_single_line(); - } + let mut option = WhereClauseOption::snuggled(&ref_and_type); + let snippet = context.snippet(item.span); + let open_pos = snippet.find_uncommented("{")? + 1; + if !contains_comment(&snippet[open_pos..]) + && items.is_empty() + && generics.where_clause.predicates.len() == 1 + && !result.contains('\n') + { + option.suppress_comma(); + option.snuggle(); + option.allow_single_line(); + } - let missing_span = mk_sp(self_ty.span.hi(), item.span.hi()); - let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{"); - let where_clause_str = rewrite_where_clause( - context, - &generics.where_clause, - context.config.brace_style(), - Shape::legacy(where_budget, offset.block_only()), - false, - "{", - where_span_end, - self_ty.span.hi(), - option, - )?; + let missing_span = mk_sp(self_ty.span.hi(), item.span.hi()); + let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{"); + let where_clause_str = rewrite_where_clause( + context, + &generics.where_clause, + context.config.brace_style(), + Shape::legacy(where_budget, offset.block_only()), + false, + "{", + where_span_end, + self_ty.span.hi(), + option, + )?; - // If there is no where-clause, we may have missing comments between the trait name and - // the opening brace. - if generics.where_clause.predicates.is_empty() { - if let Some(hi) = where_span_end { - match recover_missing_comment_in_span( - mk_sp(self_ty.span.hi(), hi), - Shape::indented(offset, context.config), - context, - last_line_width(&result), - ) { - Some(ref missing_comment) if !missing_comment.is_empty() => { - result.push_str(missing_comment); - } - _ => (), + // If there is no where-clause, we may have missing comments between the trait name and + // the opening brace. + if generics.where_clause.predicates.is_empty() { + if let Some(hi) = where_span_end { + match recover_missing_comment_in_span( + mk_sp(self_ty.span.hi(), hi), + Shape::indented(offset, context.config), + context, + last_line_width(&result), + ) { + Some(ref missing_comment) if !missing_comment.is_empty() => { + result.push_str(missing_comment); } + _ => (), } } + } - if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? { - result.push_str(&where_clause_str); - if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { - // if the where_clause contains extra comments AND - // there is only one where-clause predicate - // recover the suppressed comma in single line where_clause formatting - if generics.where_clause.predicates.len() == 1 { - result.push(','); - } - result.push_str(&format!("{}{{{}}}", sep, sep)); - } else { - result.push_str(" {}"); + if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? { + result.push_str(&where_clause_str); + if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { + // if the where_clause contains extra comments AND + // there is only one where-clause predicate + // recover the suppressed comma in single line where_clause formatting + if generics.where_clause.predicates.len() == 1 { + result.push(','); } - return Some(result); + result.push_str(&format!("{}{{{}}}", sep, sep)); + } else { + result.push_str(" {}"); } + return Some(result); + } - result.push_str(&where_clause_str); + result.push_str(&where_clause_str); - let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n'); - match context.config.brace_style() { - _ if need_newline => result.push_str(&sep), - BraceStyle::AlwaysNextLine => result.push_str(&sep), - BraceStyle::PreferSameLine => result.push(' '), - BraceStyle::SameLineWhere => { - if !where_clause_str.is_empty() { - result.push_str(&sep); - } else { - result.push(' '); - } + let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n'); + match context.config.brace_style() { + _ if need_newline => result.push_str(&sep), + BraceStyle::AlwaysNextLine => result.push_str(&sep), + BraceStyle::PreferSameLine => result.push(' '), + BraceStyle::SameLineWhere => { + if !where_clause_str.is_empty() { + result.push_str(&sep); + } else { + result.push(' '); } } + } - result.push('{'); - // this is an impl body snippet(impl SampleImpl { /* here */ }) - let lo = max(self_ty.span.hi(), generics.where_clause.span.hi()); - let snippet = context.snippet(mk_sp(lo, item.span.hi())); - let open_pos = snippet.find_uncommented("{")? + 1; + result.push('{'); + // this is an impl body snippet(impl SampleImpl { /* here */ }) + let lo = max(self_ty.span.hi(), generics.where_clause.span.hi()); + let snippet = context.snippet(mk_sp(lo, item.span.hi())); + let open_pos = snippet.find_uncommented("{")? + 1; - if !items.is_empty() || contains_comment(&snippet[open_pos..]) { - let mut visitor = FmtVisitor::from_context(context); - let item_indent = offset.block_only().block_indent(context.config); - visitor.block_indent = item_indent; - visitor.last_pos = lo + BytePos(open_pos as u32); + if !items.is_empty() || contains_comment(&snippet[open_pos..]) { + let mut visitor = FmtVisitor::from_context(context); + let item_indent = offset.block_only().block_indent(context.config); + visitor.block_indent = item_indent; + visitor.last_pos = lo + BytePos(open_pos as u32); - visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner); - visitor.visit_impl_items(items); + visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner); + visitor.visit_impl_items(items); - visitor.format_missing(item.span.hi() - BytePos(1)); + visitor.format_missing(item.span.hi() - BytePos(1)); - let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config); - let outer_indent_str = offset.block_only().to_string_with_newline(context.config); + let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config); + let outer_indent_str = offset.block_only().to_string_with_newline(context.config); - result.push_str(&inner_indent_str); - result.push_str(visitor.buffer.trim()); - result.push_str(&outer_indent_str); - } else if need_newline || !context.config.empty_item_single_line() { - result.push_str(&sep); - } + result.push_str(&inner_indent_str); + result.push_str(visitor.buffer.trim()); + result.push_str(&outer_indent_str); + } else if need_newline || !context.config.empty_item_single_line() { + result.push_str(&sep); + } - result.push('}'); + result.push('}'); - Some(result) - } else { - unreachable!(); - } + Some(result) } fn is_impl_single_line( @@ -830,111 +802,106 @@ fn is_impl_single_line( fn format_impl_ref_and_type( context: &RewriteContext<'_>, item: &ast::Item, + iimpl: &ast::Impl, offset: Indent, ) -> Option { - if let ast::ItemKind::Impl(impl_kind) = &item.kind { - let ast::Impl { - unsafety, - polarity, - defaultness, - constness, - ref generics, - of_trait: ref trait_ref, - ref self_ty, - .. - } = **impl_kind; - let mut result = String::with_capacity(128); + let ast::Impl { + unsafety, + polarity, + defaultness, + constness, + ref generics, + of_trait: ref trait_ref, + ref self_ty, + .. + } = *iimpl; + let mut result = String::with_capacity(128); - result.push_str(&format_visibility(context, &item.vis)); - result.push_str(format_defaultness(defaultness)); - result.push_str(format_unsafety(unsafety)); + result.push_str(&format_visibility(context, &item.vis)); + result.push_str(format_defaultness(defaultness)); + result.push_str(format_unsafety(unsafety)); - let shape = if context.config.version() == Version::Two { - Shape::indented(offset + last_line_width(&result), context.config) - } else { - generics_shape_from_config( - context.config, - Shape::indented(offset + last_line_width(&result), context.config), - 0, - )? - }; - let generics_str = rewrite_generics(context, "impl", generics, shape)?; - result.push_str(&generics_str); - result.push_str(format_constness_right(constness)); + let shape = if context.config.version() == Version::Two { + Shape::indented(offset + last_line_width(&result), context.config) + } else { + generics_shape_from_config( + context.config, + Shape::indented(offset + last_line_width(&result), context.config), + 0, + )? + }; + let generics_str = rewrite_generics(context, "impl", generics, shape)?; + result.push_str(&generics_str); + result.push_str(format_constness_right(constness)); - let polarity_str = match polarity { - ast::ImplPolarity::Negative(_) => "!", - ast::ImplPolarity::Positive => "", - }; + let polarity_str = match polarity { + ast::ImplPolarity::Negative(_) => "!", + ast::ImplPolarity::Positive => "", + }; - let polarity_overhead; - let trait_ref_overhead; - if let Some(ref trait_ref) = *trait_ref { - let result_len = last_line_width(&result); - result.push_str(&rewrite_trait_ref( - context, - trait_ref, - offset, - polarity_str, - result_len, - )?); - polarity_overhead = 0; // already written - trait_ref_overhead = " for".len(); - } else { - polarity_overhead = polarity_str.len(); - trait_ref_overhead = 0; - } + let polarity_overhead; + let trait_ref_overhead; + if let Some(ref trait_ref) = *trait_ref { + let result_len = last_line_width(&result); + result.push_str(&rewrite_trait_ref( + context, + trait_ref, + offset, + polarity_str, + result_len, + )?); + polarity_overhead = 0; // already written + trait_ref_overhead = " for".len(); + } else { + polarity_overhead = polarity_str.len(); + trait_ref_overhead = 0; + } - // Try to put the self type in a single line. - let curly_brace_overhead = if generics.where_clause.predicates.is_empty() { - // If there is no where-clause adapt budget for type formatting to take space and curly - // brace into account. - match context.config.brace_style() { - BraceStyle::AlwaysNextLine => 0, - _ => 2, - } - } else { - 0 - }; - let used_space = last_line_width(&result) - + polarity_overhead - + trait_ref_overhead - + curly_brace_overhead; - // 1 = space before the type. - let budget = context.budget(used_space + 1); - if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) { - if !self_ty_str.contains('\n') { - if trait_ref.is_some() { - result.push_str(" for "); - } else { - result.push(' '); - result.push_str(polarity_str); - } - result.push_str(&self_ty_str); - return Some(result); + // Try to put the self type in a single line. + let curly_brace_overhead = if generics.where_clause.predicates.is_empty() { + // If there is no where-clause adapt budget for type formatting to take space and curly + // brace into account. + match context.config.brace_style() { + BraceStyle::AlwaysNextLine => 0, + _ => 2, + } + } else { + 0 + }; + let used_space = + last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead; + // 1 = space before the type. + let budget = context.budget(used_space + 1); + if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) { + if !self_ty_str.contains('\n') { + if trait_ref.is_some() { + result.push_str(" for "); + } else { + result.push(' '); + result.push_str(polarity_str); } + result.push_str(&self_ty_str); + return Some(result); } + } - // Couldn't fit the self type on a single line, put it on a new line. - result.push('\n'); - // Add indentation of one additional tab. - let new_line_offset = offset.block_indent(context.config); - result.push_str(&new_line_offset.to_string(context.config)); - if trait_ref.is_some() { - result.push_str("for "); - } else { - result.push_str(polarity_str); - } - let budget = context.budget(last_line_width(&result) + polarity_overhead); - let type_offset = match context.config.indent_style() { - IndentStyle::Visual => new_line_offset + trait_ref_overhead, - IndentStyle::Block => new_line_offset, - }; - result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?); - Some(result) + // Couldn't fit the self type on a single line, put it on a new line. + result.push('\n'); + // Add indentation of one additional tab. + let new_line_offset = offset.block_indent(context.config); + result.push_str(&new_line_offset.to_string(context.config)); + if trait_ref.is_some() { + result.push_str("for "); } else { - unreachable!(); + result.push_str(polarity_str); } + let budget = context.budget(last_line_width(&result) + polarity_overhead); + let type_offset = match context.config.indent_style() { + IndentStyle::Visual => new_line_offset + trait_ref_overhead, + IndentStyle::Block => new_line_offset, + }; + result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?); + Some(result) } fn rewrite_trait_ref( diff --git a/src/visitor.rs b/src/visitor.rs index 527042d098a1c..e4a7be742abcb 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -485,9 +485,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { if should_visit_node_again { match item.kind { ast::ItemKind::Use(ref tree) => self.format_import(item, tree), - ast::ItemKind::Impl { .. } => { + ast::ItemKind::Impl(ref iimpl) => { let block_indent = self.block_indent; - let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent)); + let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent)); self.push_rewrite(item.span, rw); } ast::ItemKind::Trait(..) => { From 0023abfb2c826d8a9ff74146ece513b22b86fdce Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Thu, 18 Nov 2021 12:38:34 -0600 Subject: [PATCH 04/16] tests: add cases for type alias issues --- tests/source/issue_4823.rs | 5 +++++ tests/source/issue_5027.rs | 7 +++++++ tests/source/issue_5086.rs | 2 ++ tests/target/issue_4823.rs | 5 +++++ tests/target/issue_5027.rs | 17 +++++++++++++++++ tests/target/issue_5086.rs | 2 ++ 6 files changed, 38 insertions(+) create mode 100644 tests/source/issue_4823.rs create mode 100644 tests/source/issue_5027.rs create mode 100644 tests/source/issue_5086.rs create mode 100644 tests/target/issue_4823.rs create mode 100644 tests/target/issue_5027.rs create mode 100644 tests/target/issue_5086.rs diff --git a/tests/source/issue_4823.rs b/tests/source/issue_4823.rs new file mode 100644 index 0000000000000..a008dd3d83817 --- /dev/null +++ b/tests/source/issue_4823.rs @@ -0,0 +1,5 @@ +macro_rules! m { +() => { +type Type; +}; +} diff --git a/tests/source/issue_5027.rs b/tests/source/issue_5027.rs new file mode 100644 index 0000000000000..67beeb23b7114 --- /dev/null +++ b/tests/source/issue_5027.rs @@ -0,0 +1,7 @@ +// rustfmt-version: Two + +pub type Iter<'a, D> = impl DoubleEndedIterator)>+ ExactSizeIterator+ 'a; + +trait FOo {pub type Iter<'a, D> = impl DoubleEndedIterator)>+ ExactSizeIterator+ 'a;} + +impl Bar {pub type Iter<'a, D> = impl DoubleEndedIterator)>+ ExactSizeIterator+ 'a;} \ No newline at end of file diff --git a/tests/source/issue_5086.rs b/tests/source/issue_5086.rs new file mode 100644 index 0000000000000..1644c9d2ccbbb --- /dev/null +++ b/tests/source/issue_5086.rs @@ -0,0 +1,2 @@ +#[cfg(any())] + type Type : Bound ; \ No newline at end of file diff --git a/tests/target/issue_4823.rs b/tests/target/issue_4823.rs new file mode 100644 index 0000000000000..de17467c0efad --- /dev/null +++ b/tests/target/issue_4823.rs @@ -0,0 +1,5 @@ +macro_rules! m { + () => { + type Type; + }; +} diff --git a/tests/target/issue_5027.rs b/tests/target/issue_5027.rs new file mode 100644 index 0000000000000..26d771720b6c5 --- /dev/null +++ b/tests/target/issue_5027.rs @@ -0,0 +1,17 @@ +// rustfmt-version: Two + +pub type Iter<'a, D> = impl DoubleEndedIterator)> + + ExactSizeIterator + + 'a; + +trait FOo { + pub type Iter<'a, D> = impl DoubleEndedIterator)> + + ExactSizeIterator + + 'a; +} + +impl Bar { + type Iter<'a, D> = impl DoubleEndedIterator)> + + ExactSizeIterator + + 'a; +} diff --git a/tests/target/issue_5086.rs b/tests/target/issue_5086.rs new file mode 100644 index 0000000000000..7a0be06f7917a --- /dev/null +++ b/tests/target/issue_5086.rs @@ -0,0 +1,2 @@ +#[cfg(any())] +type Type: Bound; From 2c442ccf25a98c9e8f0a972d94f10ef44b7b09bf Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Thu, 18 Nov 2021 12:39:38 -0600 Subject: [PATCH 05/16] fix: correct some type alias issues --- src/items.rs | 49 ++++++++++++++++++++++++------------------------- src/types.rs | 8 ++++++++ 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/items.rs b/src/items.rs index 849e6c06218f8..63c32e012df7f 100644 --- a/src/items.rs +++ b/src/items.rs @@ -28,6 +28,7 @@ use crate::shape::{Indent, Shape}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; use crate::stmt::Stmt; +use crate::types::opaque_ty; use crate::utils::*; use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; @@ -581,13 +582,10 @@ impl<'a> FmtVisitor<'a> { if self.get_context().config.reorder_impl_items() { type TyOpt = Option>; use crate::ast::AssocItemKind::*; - let is_type = |ty: &TyOpt| { - ty.as_ref() - .map_or(true, |t| !matches!(t.kind, ast::TyKind::ImplTrait(..))) - }; - let is_opaque = |ty: &TyOpt| !is_type(ty); - let both_type = |left: &TyOpt, right: &TyOpt| is_type(left) && is_type(right); - let both_opaque = |left: &TyOpt, right: &TyOpt| is_opaque(left) && is_opaque(right); + let is_type = |ty: &TyOpt| opaque_ty(ty).is_none(); + let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some(); + let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r); + let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r); let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) { (TyAlias(lty), TyAlias(rty)) if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) => @@ -1508,43 +1506,38 @@ pub(crate) fn rewrite_type_alias<'a, 'b>( ref bounds, ref ty, } = *ty_alias_kind; - let ty_opt = ty.as_ref().map(|t| &**t); + let ty_opt = ty.as_ref(); let (ident, vis) = match visitor_kind { Item(i) => (i.ident, &i.vis), AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis), ForeignItem(i) => (i.ident, &i.vis), }; let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span); - + let op_ty = opaque_ty(ty); // Type Aliases are formatted slightly differently depending on the context // in which they appear, whether they are opaque, and whether they are associated. // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html // /~https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases - match (visitor_kind, ty_opt) { - (Item(_), None) => { - let op_ty = OpaqueType { bounds }; - rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis) + match (visitor_kind, &op_ty) { + (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(ref op_bounds)) => { + let op = OpaqueType { bounds: op_bounds }; + rewrite_ty(rw_info, Some(bounds), Some(&op), vis) + } + (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => { + rewrite_ty(rw_info, Some(bounds), ty_opt, vis) } - (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis), (AssocImplItem(_), _) => { - let result = if let Some(ast::Ty { - kind: ast::TyKind::ImplTrait(_, ref bounds), - .. - }) = ty_opt - { - let op_ty = OpaqueType { bounds }; - rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY) + let result = if let Some(ref op_bounds) = op_ty { + let op = OpaqueType { bounds: op_bounds }; + rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY) } else { - rewrite_ty(rw_info, None, ty.as_ref(), vis) + rewrite_ty(rw_info, Some(bounds), ty_opt, vis) }?; match defaultness { ast::Defaultness::Default(..) => Some(format!("default {}", result)), _ => Some(result), } } - (AssocTraitItem(_), _) | (ForeignItem(_), _) => { - rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis) - } } } @@ -1867,6 +1860,12 @@ fn rewrite_static( Some(format!("{}{};", prefix, ty_str)) } } + +// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait. +// This should be removed once that bug is resolved, with the type alias formatting using the +// defined Ty for the RHS directly. +// /~https://github.com/rust-lang/rustfmt/issues/4373 +// /~https://github.com/rust-lang/rustfmt/issues/5027 struct OpaqueType<'a> { bounds: &'a ast::GenericBounds, } diff --git a/src/types.rs b/src/types.rs index 9ea90c5e46dd8..891609783b61b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,6 +2,7 @@ use std::iter::ExactSizeIterator; use std::ops::Deref; use rustc_ast::ast::{self, FnRetTy, Mutability}; +use rustc_ast::ptr; use rustc_span::{symbol::kw, BytePos, Pos, Span}; use crate::comment::{combine_strs_with_missing_comments, contains_comment}; @@ -1031,6 +1032,13 @@ fn join_bounds_inner( } } +pub(crate) fn opaque_ty(ty: &Option>) -> Option<&ast::GenericBounds> { + ty.as_ref().and_then(|t| match &t.kind { + ast::TyKind::ImplTrait(_, bounds) => Some(bounds), + _ => None, + }) +} + pub(crate) fn can_be_overflowed_type( context: &RewriteContext<'_>, ty: &ast::Ty, From 196e6765048b8306208ac88d743ab02e8faf4b6b Mon Sep 17 00:00:00 2001 From: mujpao Date: Thu, 18 Nov 2021 17:06:49 -0800 Subject: [PATCH 06/16] Preserve normalized comments after last list item --- src/lists.rs | 13 +- .../wrap-comments-not-normalized.rs | 108 ++++++++++++++++ tests/source/issue-4909/wrap-comments-true.rs | 109 ++++++++++++++++ .../target/issue-4909/wrap-comments-false.rs | 72 +++++++++++ .../wrap-comments-not-normalized.rs | 118 +++++++++++++++++ tests/target/issue-4909/wrap-comments-true.rs | 119 ++++++++++++++++++ 6 files changed, 535 insertions(+), 4 deletions(-) create mode 100644 tests/source/issue-4909/wrap-comments-not-normalized.rs create mode 100644 tests/source/issue-4909/wrap-comments-true.rs create mode 100644 tests/target/issue-4909/wrap-comments-false.rs create mode 100644 tests/target/issue-4909/wrap-comments-not-normalized.rs create mode 100644 tests/target/issue-4909/wrap-comments-true.rs diff --git a/src/lists.rs b/src/lists.rs index d341ec8e6b0e7..3515dd172510c 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -444,10 +444,15 @@ where let offset = formatting.shape.indent + overhead; let comment_shape = Shape::legacy(width, offset); - // Use block-style only for the last item or multiline comments. - let block_style = !formatting.ends_with_newline && last - || comment.trim().contains('\n') - || comment.trim().len() > width; + let block_style = if !formatting.ends_with_newline && last { + true + } else if starts_with_newline(comment) { + false + } else if comment.trim().contains('\n') || comment.trim().len() > width { + true + } else { + false + }; rewrite_comment( comment.trim_start(), diff --git a/tests/source/issue-4909/wrap-comments-not-normalized.rs b/tests/source/issue-4909/wrap-comments-not-normalized.rs new file mode 100644 index 0000000000000..cd8de2707f160 --- /dev/null +++ b/tests/source/issue-4909/wrap-comments-not-normalized.rs @@ -0,0 +1,108 @@ +// rustfmt-wrap_comments: true + +pub enum E { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub enum E2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub enum E3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + +} + +pub struct S { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub struct S2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub struct S3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions +} + +fn foo( + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo2(// Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo3( + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + +) -> usize { + 5 +} + +fn main() { + let v = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v2: Vec = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v3 = vec![ + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + ]; +} diff --git a/tests/source/issue-4909/wrap-comments-true.rs b/tests/source/issue-4909/wrap-comments-true.rs new file mode 100644 index 0000000000000..f18d8d686e1f3 --- /dev/null +++ b/tests/source/issue-4909/wrap-comments-true.rs @@ -0,0 +1,109 @@ +// rustfmt-normalize_comments: true +// rustfmt-wrap_comments: true + +pub enum E { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub enum E2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub enum E3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + +} + +pub struct S { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub struct S2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub struct S3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions +} + +fn foo( + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo2(// Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo3( + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + +) -> usize { + 5 +} + +fn main() { + let v = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v2: Vec = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v3 = vec![ + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + ]; +} diff --git a/tests/target/issue-4909/wrap-comments-false.rs b/tests/target/issue-4909/wrap-comments-false.rs new file mode 100644 index 0000000000000..a8ead584f4459 --- /dev/null +++ b/tests/target/issue-4909/wrap-comments-false.rs @@ -0,0 +1,72 @@ +// rustfmt-normalize_comments: true + +pub enum E { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub enum E2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub struct S { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub struct S2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +fn foo( + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo2(// Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn main() { + let v = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v2: Vec = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; +} diff --git a/tests/target/issue-4909/wrap-comments-not-normalized.rs b/tests/target/issue-4909/wrap-comments-not-normalized.rs new file mode 100644 index 0000000000000..2a3d803b3b1e4 --- /dev/null +++ b/tests/target/issue-4909/wrap-comments-not-normalized.rs @@ -0,0 +1,118 @@ +// rustfmt-wrap_comments: true + +pub enum E { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub enum E2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub enum E3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions +} + +pub struct S { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub struct S2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub struct S3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions +} + +fn foo( + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo2(// Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo3( + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn main() { + let v = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v2: Vec = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v3 = vec![ + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + ]; +} diff --git a/tests/target/issue-4909/wrap-comments-true.rs b/tests/target/issue-4909/wrap-comments-true.rs new file mode 100644 index 0000000000000..5376962a2ee41 --- /dev/null +++ b/tests/target/issue-4909/wrap-comments-true.rs @@ -0,0 +1,119 @@ +// rustfmt-normalize_comments: true +// rustfmt-wrap_comments: true + +pub enum E { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub enum E2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub enum E3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions +} + +pub struct S { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub struct S2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub struct S3 { + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions +} + +fn foo( + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo2(// Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo3( + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage through the inclusion + // pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn main() { + let v = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v2: Vec = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v3 = vec![ + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + ]; +} From 826eba8984690b7c23aab8604b6a85587bb93edb Mon Sep 17 00:00:00 2001 From: Johannes Linke Date: Sat, 20 Nov 2021 02:22:50 +0100 Subject: [PATCH 07/16] Add a few missing tracking issues in Configurations.md (#5084) * Add a few missing tracking issues in Configurations.md * fix: tracking issue for imports_granularity stabilization Co-authored-by: Caleb Cartwright --- Configurations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Configurations.md b/Configurations.md index 4a281251f2275..a89fbe863e652 100644 --- a/Configurations.md +++ b/Configurations.md @@ -933,7 +933,7 @@ if any of the first five lines contains `@generated` marker. - **Default value**: `false` - **Possible values**: `true`, `false` -- **Stable**: No +- **Stable**: No (tracking issue: [#5080](/~https://github.com/rust-lang/rustfmt/issues/5080)) ## `format_macro_matchers` @@ -1064,7 +1064,7 @@ Control the case of the letters in hexadecimal literal values - **Default value**: `Preserve` - **Possible values**: `Upper`, `Lower` -- **Stable**: No +- **Stable**: No (tracking issue: [#5081](/~https://github.com/rust-lang/rustfmt/issues/5081)) ## `hide_parse_errors` @@ -1701,7 +1701,7 @@ How imports should be grouped into `use` statements. Imports will be merged or s - **Default value**: `Preserve` - **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One` -- **Stable**: No +- **Stable**: No (tracking issue: [#4991](/~https://github.com/rust-lang/rustfmt/issues/4991)) #### `Preserve` (default): @@ -2063,7 +2063,7 @@ Controls the strategy for how imports are grouped together. - **Default value**: `Preserve` - **Possible values**: `Preserve`, `StdExternalCrate`, `One` -- **Stable**: No +- **Stable**: No (tracking issue: [#5083](/~https://github.com/rust-lang/rustfmt/issues/5083)) #### `Preserve` (default): From 4389a4ce49e737915af1f1b27b96b05598a4e388 Mon Sep 17 00:00:00 2001 From: Dom Date: Fri, 19 Nov 2021 20:15:33 +0100 Subject: [PATCH 08/16] fix: do not wrap reference-style doc links Prevents wrap_comments from incorrectly wrapping reference-style doc links. --- src/comment.rs | 19 ++++++++++++++++++- tests/target/issue-5095.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/target/issue-5095.rs diff --git a/src/comment.rs b/src/comment.rs index 7b76c232937dc..830d2b50aad82 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -3,6 +3,8 @@ use std::{self, borrow::Cow, iter}; use itertools::{multipeek, MultiPeek}; +use lazy_static::lazy_static; +use regex::Regex; use rustc_span::Span; use crate::config::Config; @@ -15,6 +17,17 @@ use crate::utils::{ }; use crate::{ErrorKind, FormattingError}; +lazy_static! { + /// A regex matching reference doc links. + /// + /// ```markdown + /// /// An [example]. + /// /// + /// /// [example]: this::is::a::link + /// ``` + static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap(); +} + fn is_custom_comment(comment: &str) -> bool { if !comment.starts_with("//") { false @@ -842,7 +855,11 @@ fn trim_custom_comment_prefix(s: &str) -> String { /// Returns `true` if the given string MAY include URLs or alike. fn has_url(s: &str) -> bool { // This function may return false positive, but should get its job done in most cases. - s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://") + s.contains("https://") + || s.contains("http://") + || s.contains("ftp://") + || s.contains("file://") + || REFERENCE_LINK_URL.is_match(s) } /// Given the span, rewrite the missing comment inside it if available. diff --git a/tests/target/issue-5095.rs b/tests/target/issue-5095.rs new file mode 100644 index 0000000000000..6981a65808c90 --- /dev/null +++ b/tests/target/issue-5095.rs @@ -0,0 +1,27 @@ +// rustfmt-wrap_comments: true + +pub mod a_long_name { + pub mod b_long_name { + pub mod c_long_name { + pub mod d_long_name { + pub mod e_long_name { + pub struct Bananas; + impl Bananas { + pub fn fantastic() {} + } + + pub mod f_long_name { + pub struct Apples; + } + } + } + } + } +} + +/// Check out [my other struct] ([`Bananas`]) and [the method it has]. +/// +/// [my other struct]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::f_long_name::Apples +/// [`Bananas`]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic() +/// [the method it has]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic() +pub struct A; From f99469d7c446e95da1e41ecb224abf6721e2f599 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Wed, 24 Nov 2021 17:11:15 +0000 Subject: [PATCH 09/16] Change how the fn params span is calculated Use the available Generics span field to avoid issues with `T: Fn()` bounds. This is necessary to land #85346. --- src/items.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/items.rs b/src/items.rs index 50121a8b6b50e..acc91f861e474 100644 --- a/src/items.rs +++ b/src/items.rs @@ -2236,18 +2236,10 @@ fn rewrite_fn_base( result.push_str(¶m_indent.to_string_with_newline(context.config)); } - // Skip `pub(crate)`. - let lo_after_visibility = get_bytepos_after_visibility(fn_sig.visibility, span); - // A conservative estimation, the goal is to be over all parens in generics - let params_start = fn_sig - .generics - .params - .last() - .map_or(lo_after_visibility, |param| param.span().hi()); let params_end = if fd.inputs.is_empty() { context .snippet_provider - .span_after(mk_sp(params_start, span.hi()), ")") + .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")") } else { let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi()); context.snippet_provider.span_after(last_span, ")") @@ -2255,7 +2247,7 @@ fn rewrite_fn_base( let params_span = mk_sp( context .snippet_provider - .span_after(mk_sp(params_start, span.hi()), "("), + .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("), params_end, ); let param_str = rewrite_params( From 243cec7a0b9cc0ba3fba6e5ed849b0635f3496db Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Wed, 24 Nov 2021 10:38:55 +0100 Subject: [PATCH 10/16] Update README.md --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b3d21e6fb87c7..b3a968f0c043e 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,11 @@ cargo +nightly fmt ## Limitations Rustfmt tries to work on as much Rust code as possible. Sometimes, the code -doesn't even need to compile! As we approach a 1.0 release we are also looking -to limit areas of instability; in particular, post-1.0, the formatting of most -code should not change as Rustfmt improves. However, there are some things that -Rustfmt can't do or can't do well (and thus where formatting might change -significantly, even post-1.0). We would like to reduce the list of limitations -over time. +doesn't even need to compile! In general, we are looking to limit areas of +instability; in particular, post-1.0, the formatting of most code should not +change as Rustfmt improves. However, there are some things that Rustfmt can't +do or can't do well (and thus where formatting might change significantly, +even post-1.0). We would like to reduce the list of limitations over time. The following list enumerates areas where Rustfmt does not work or where the stability guarantees do not apply (we don't make a distinction between the two From ea042b90c9b66cf5431acddd29e54468c05ea65b Mon Sep 17 00:00:00 2001 From: mujpao Date: Wed, 24 Nov 2021 15:05:23 -0800 Subject: [PATCH 11/16] Add more tests for comments in lists --- .../wrap-comments-not-normalized.rs | 21 ++++ .../wrap-comments-true.rs | 21 ++++ .../comments-in-lists/format-doc-comments.rs | 96 +++++++++++++++++++ .../wrap-comments-false.rs | 13 +++ .../wrap-comments-not-normalized.rs | 24 +++++ .../wrap-comments-true.rs | 24 +++++ 6 files changed, 199 insertions(+) rename tests/source/{issue-4909 => comments-in-lists}/wrap-comments-not-normalized.rs (81%) rename tests/source/{issue-4909 => comments-in-lists}/wrap-comments-true.rs (81%) create mode 100644 tests/target/comments-in-lists/format-doc-comments.rs rename tests/target/{issue-4909 => comments-in-lists}/wrap-comments-false.rs (82%) rename tests/target/{issue-4909 => comments-in-lists}/wrap-comments-not-normalized.rs (81%) rename tests/target/{issue-4909 => comments-in-lists}/wrap-comments-true.rs (81%) diff --git a/tests/source/issue-4909/wrap-comments-not-normalized.rs b/tests/source/comments-in-lists/wrap-comments-not-normalized.rs similarity index 81% rename from tests/source/issue-4909/wrap-comments-not-normalized.rs rename to tests/source/comments-in-lists/wrap-comments-not-normalized.rs index cd8de2707f160..b96c02802d69c 100644 --- a/tests/source/issue-4909/wrap-comments-not-normalized.rs +++ b/tests/source/comments-in-lists/wrap-comments-not-normalized.rs @@ -1,5 +1,6 @@ // rustfmt-wrap_comments: true +// /~https://github.com/rust-lang/rustfmt/issues/4909 pub enum E { // Expand as needed, numbers should be ascending according to the stage // through the inclusion pipeline, or according to the descriptions @@ -105,4 +106,24 @@ fn main() { 2, // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions ]; + + // /~https://github.com/rust-lang/rustfmt/issues/4430 + match a { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + } + + match a { + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + } } diff --git a/tests/source/issue-4909/wrap-comments-true.rs b/tests/source/comments-in-lists/wrap-comments-true.rs similarity index 81% rename from tests/source/issue-4909/wrap-comments-true.rs rename to tests/source/comments-in-lists/wrap-comments-true.rs index f18d8d686e1f3..360b838520eda 100644 --- a/tests/source/issue-4909/wrap-comments-true.rs +++ b/tests/source/comments-in-lists/wrap-comments-true.rs @@ -1,6 +1,7 @@ // rustfmt-normalize_comments: true // rustfmt-wrap_comments: true +// /~https://github.com/rust-lang/rustfmt/issues/4909 pub enum E { // Expand as needed, numbers should be ascending according to the stage // through the inclusion pipeline, or according to the descriptions @@ -106,4 +107,24 @@ fn main() { 2, // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions ]; + + // /~https://github.com/rust-lang/rustfmt/issues/4430 + match a { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + } + + match a { + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions + } } diff --git a/tests/target/comments-in-lists/format-doc-comments.rs b/tests/target/comments-in-lists/format-doc-comments.rs new file mode 100644 index 0000000000000..be31bf0a33198 --- /dev/null +++ b/tests/target/comments-in-lists/format-doc-comments.rs @@ -0,0 +1,96 @@ +// rustfmt-format_code_in_doc_comments: true + +// /~https://github.com/rust-lang/rustfmt/issues/4420 +enum Minimal { + Example, + //[thisisremoved thatsleft + // canbeanything +} + +struct Minimal2 { + Example: usize, + //[thisisremoved thatsleft + // canbeanything +} + +pub enum E { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + Variant2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub enum E2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +pub struct S { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + some_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + last_field: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +} + +pub struct S2 { + // This can be changed once /~https://github.com/rust-lang/rustfmt/issues/4854 is fixed +// Expand as needed, numbers should be ascending according to the stage +// through the inclusion pipeline, or according to the descriptions +} + +fn foo( + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + a: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b: usize, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn foo2(// Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions +) -> usize { + 5 +} + +fn main() { + let v = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 1, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + 2, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + let v2: Vec = vec![ + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + ]; + + match a { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + } +} diff --git a/tests/target/issue-4909/wrap-comments-false.rs b/tests/target/comments-in-lists/wrap-comments-false.rs similarity index 82% rename from tests/target/issue-4909/wrap-comments-false.rs rename to tests/target/comments-in-lists/wrap-comments-false.rs index a8ead584f4459..80aea59d1b520 100644 --- a/tests/target/issue-4909/wrap-comments-false.rs +++ b/tests/target/comments-in-lists/wrap-comments-false.rs @@ -1,5 +1,6 @@ // rustfmt-normalize_comments: true +// /~https://github.com/rust-lang/rustfmt/issues/4909 pub enum E { // Expand as needed, numbers should be ascending according to the stage // through the inclusion pipeline, or according to the descriptions @@ -69,4 +70,16 @@ fn main() { // Expand as needed, numbers should be ascending according to the stage // through the inclusion pipeline, or according to the descriptions ]; + + // /~https://github.com/rust-lang/rustfmt/issues/4430 + match a { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + } } diff --git a/tests/target/issue-4909/wrap-comments-not-normalized.rs b/tests/target/comments-in-lists/wrap-comments-not-normalized.rs similarity index 81% rename from tests/target/issue-4909/wrap-comments-not-normalized.rs rename to tests/target/comments-in-lists/wrap-comments-not-normalized.rs index 2a3d803b3b1e4..52315f470e4b9 100644 --- a/tests/target/issue-4909/wrap-comments-not-normalized.rs +++ b/tests/target/comments-in-lists/wrap-comments-not-normalized.rs @@ -1,5 +1,6 @@ // rustfmt-wrap_comments: true +// /~https://github.com/rust-lang/rustfmt/issues/4909 pub enum E { // Expand as needed, numbers should be ascending according to the stage // through the inclusion pipeline, or according to the descriptions @@ -115,4 +116,27 @@ fn main() { // Expand as needed, numbers should be ascending according to the stage through the // inclusion pipeline, or according to the descriptions ]; + + // /~https://github.com/rust-lang/rustfmt/issues/4430 + match a { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + } + + match a { + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + } } diff --git a/tests/target/issue-4909/wrap-comments-true.rs b/tests/target/comments-in-lists/wrap-comments-true.rs similarity index 81% rename from tests/target/issue-4909/wrap-comments-true.rs rename to tests/target/comments-in-lists/wrap-comments-true.rs index 5376962a2ee41..e0bfcf0b5007d 100644 --- a/tests/target/issue-4909/wrap-comments-true.rs +++ b/tests/target/comments-in-lists/wrap-comments-true.rs @@ -1,6 +1,7 @@ // rustfmt-normalize_comments: true // rustfmt-wrap_comments: true +// /~https://github.com/rust-lang/rustfmt/issues/4909 pub enum E { // Expand as needed, numbers should be ascending according to the stage // through the inclusion pipeline, or according to the descriptions @@ -116,4 +117,27 @@ fn main() { // Expand as needed, numbers should be ascending according to the stage through the // inclusion pipeline, or according to the descriptions ]; + + // /~https://github.com/rust-lang/rustfmt/issues/4430 + match a { + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage + // through the inclusion pipeline, or according to the descriptions + } + + match a { + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + b => c, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + d => e, + // Expand as needed, numbers should be ascending according to the stage through the + // inclusion pipeline, or according to the descriptions + } } From 67fd9ec3002d269c272f68fa0e34a1cb2ca5fd08 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 24 Nov 2021 03:35:01 -0500 Subject: [PATCH 12/16] Run Windows, Linux, and Mac CI tests with nightly and stable channels --- .github/workflows/linux.yml | 5 ++++- .github/workflows/mac.yml | 5 ++++- .github/workflows/windows.yml | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 6eaae69c70805..db49794164212 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -8,7 +8,9 @@ on: jobs: test: runs-on: ubuntu-latest - name: (${{ matrix.target }}, nightly) + name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) + env: + CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} strategy: # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization. @@ -20,6 +22,7 @@ jobs: target: [ x86_64-unknown-linux-gnu, ] + cfg_release_channel: [nightly, stable] steps: - name: checkout diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 79e4f69163e03..55e1cc9539b85 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -10,13 +10,16 @@ jobs: # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources # macOS Catalina 10.15 runs-on: macos-latest - name: (${{ matrix.target }}, nightly) + name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) + env: + CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} strategy: fail-fast: false matrix: target: [ x86_64-apple-darwin, ] + cfg_release_channel: [nightly, stable] steps: - name: checkout diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c05e8d4896ac7..dcb08b5412ea6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -8,7 +8,9 @@ on: jobs: test: runs-on: windows-latest - name: (${{ matrix.target }}, nightly) + name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) + env: + CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} strategy: # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization. @@ -23,6 +25,7 @@ jobs: x86_64-pc-windows-gnu, x86_64-pc-windows-msvc, ] + cfg_release_channel: [nightly, stable] steps: # The Windows runners have autocrlf enabled by default From a21f1b6c2a5734f39a1efe3fa84d6475843d14fe Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Sat, 27 Nov 2021 17:14:15 -0500 Subject: [PATCH 13/16] Conditionally compile tests based on CFG_RELEASE_CHANNEL env var Adds the ``nightly_only_test`` and ``stable_only_test`` attribute macros that prevent or allow certain tests to compile on nightly and stable respectively. This is achieved through conditionally outputting the tests TokenStream. If CFG_RELEASE_CHANNEL is not set, it's assumed that we're running in a nightly environment. To mark a test as nightly only: #[nightly_only_test] #[test] fn only_run_on_nightly() { ... } To mark a test a stable only: #[stable_only_test] #[test] fn only_run_on_stable() { ... } --- config_proc_macro/src/lib.rs | 42 ++++++++++++++++++ src/config/mod.rs | 86 +++++++++++++++--------------------- src/syntux/session.rs | 15 +++---- src/test/mod.rs | 13 +++--- 4 files changed, 88 insertions(+), 68 deletions(-) diff --git a/config_proc_macro/src/lib.rs b/config_proc_macro/src/lib.rs index 78e7e098ed9e1..513018213192d 100644 --- a/config_proc_macro/src/lib.rs +++ b/config_proc_macro/src/lib.rs @@ -8,6 +8,8 @@ mod item_enum; mod item_struct; mod utils; +use std::str::FromStr; + use proc_macro::TokenStream; use syn::parse_macro_input; @@ -23,3 +25,43 @@ pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream { TokenStream::from(output) } + +/// Used to conditionally output the TokenStream for tests that need to be run on nightly only. +/// +/// ```rust +/// #[nightly_only_test] +/// #[test] +/// fn test_needs_nightly_rustfmt() { +/// assert!(true); +/// } +/// ``` +#[proc_macro_attribute] +pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream { + // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true + if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") { + input + } else { + // output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev" + TokenStream::from_str("").unwrap() + } +} + +/// Used to conditionally output the TokenStream for tests that need to be run on stable only. +/// +/// ```rust +/// #[stable_only_test] +/// #[test] +/// fn test_needs_stable_rustfmt() { +/// assert!(true); +/// } +/// ``` +#[proc_macro_attribute] +pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream { + // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false + if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") { + input + } else { + // output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable' + TokenStream::from_str("").unwrap() + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs index c5419d860c943..5dbe532ac388f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -405,6 +405,8 @@ mod test { use super::*; use std::str; + use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; + #[allow(dead_code)] mod mock { use super::super::*; @@ -525,21 +527,17 @@ mod test { assert!(config.license_template.is_none()); } + #[nightly_only_test] #[test] fn test_valid_license_template_path() { - if !crate::is_nightly_channel!() { - return; - } let toml = r#"license_template_path = "tests/license-template/lt.txt""#; let config = Config::from_toml(toml, Path::new("")).unwrap(); assert!(config.license_template.is_some()); } + #[nightly_only_test] #[test] fn test_override_existing_license_with_no_license() { - if !crate::is_nightly_channel!() { - return; - } let toml = r#"license_template_path = "tests/license-template/lt.txt""#; let mut config = Config::from_toml(toml, Path::new("")).unwrap(); assert!(config.license_template.is_some()); @@ -634,48 +632,42 @@ make_backup = false assert_eq!(&toml, &default_config); } - // FIXME(#2183): these tests cannot be run in parallel because they use env vars. - // #[test] - // fn test_as_not_nightly_channel() { - // let mut config = Config::default(); - // assert_eq!(config.was_set().unstable_features(), false); - // config.set().unstable_features(true); - // assert_eq!(config.was_set().unstable_features(), false); - // } - - // #[test] - // fn test_as_nightly_channel() { - // let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from("")); - // ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly"); - // let mut config = Config::default(); - // config.set().unstable_features(true); - // assert_eq!(config.was_set().unstable_features(), false); - // config.set().unstable_features(true); - // assert_eq!(config.unstable_features(), true); - // ::std::env::set_var("CFG_RELEASE_CHANNEL", v); - // } - - // #[test] - // fn test_unstable_from_toml() { - // let mut config = Config::from_toml("unstable_features = true").unwrap(); - // assert_eq!(config.was_set().unstable_features(), false); - // let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from("")); - // ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly"); - // config = Config::from_toml("unstable_features = true").unwrap(); - // assert_eq!(config.was_set().unstable_features(), true); - // assert_eq!(config.unstable_features(), true); - // ::std::env::set_var("CFG_RELEASE_CHANNEL", v); - // } + #[stable_only_test] + #[test] + fn test_as_not_nightly_channel() { + let mut config = Config::default(); + assert_eq!(config.was_set().unstable_features(), false); + config.set().unstable_features(true); + assert_eq!(config.was_set().unstable_features(), false); + } + + #[nightly_only_test] + #[test] + fn test_as_nightly_channel() { + let mut config = Config::default(); + config.set().unstable_features(true); + // When we don't set the config from toml or command line options it + // doesn't get marked as set by the user. + assert_eq!(config.was_set().unstable_features(), false); + config.set().unstable_features(true); + assert_eq!(config.unstable_features(), true); + } + + #[nightly_only_test] + #[test] + fn test_unstable_from_toml() { + let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap(); + assert_eq!(config.was_set().unstable_features(), true); + assert_eq!(config.unstable_features(), true); + } #[cfg(test)] mod deprecated_option_merge_imports { use super::*; + #[nightly_only_test] #[test] fn test_old_option_set() { - if !crate::is_nightly_channel!() { - return; - } let toml = r#" unstable_features = true merge_imports = true @@ -684,11 +676,9 @@ make_backup = false assert_eq!(config.imports_granularity(), ImportGranularity::Crate); } + #[nightly_only_test] #[test] fn test_both_set() { - if !crate::is_nightly_channel!() { - return; - } let toml = r#" unstable_features = true merge_imports = true @@ -698,11 +688,9 @@ make_backup = false assert_eq!(config.imports_granularity(), ImportGranularity::Preserve); } + #[nightly_only_test] #[test] fn test_new_overridden() { - if !crate::is_nightly_channel!() { - return; - } let toml = r#" unstable_features = true merge_imports = true @@ -712,11 +700,9 @@ make_backup = false assert_eq!(config.imports_granularity(), ImportGranularity::Preserve); } + #[nightly_only_test] #[test] fn test_old_overridden() { - if !crate::is_nightly_channel!() { - return; - } let toml = r#" unstable_features = true imports_granularity = "Module" diff --git a/src/syntux/session.rs b/src/syntux/session.rs index cdb4893d443b9..dd7c7352686e6 100644 --- a/src/syntux/session.rs +++ b/src/syntux/session.rs @@ -286,10 +286,11 @@ impl LineRangeUtils for ParseSess { mod tests { use super::*; + use rustfmt_config_proc_macro::nightly_only_test; + mod emitter { use super::*; use crate::config::IgnoreList; - use crate::is_nightly_channel; use crate::utils::mk_sp; use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP}; use std::path::PathBuf; @@ -371,11 +372,9 @@ mod tests { assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } + #[nightly_only_test] #[test] fn handles_recoverable_parse_error_in_ignored_file() { - if !is_nightly_channel!() { - return; - } let num_emitted_errors = Lrc::new(AtomicU32::new(0)); let can_reset_errors = Lrc::new(AtomicBool::new(false)); let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#); @@ -398,11 +397,9 @@ mod tests { assert_eq!(can_reset_errors.load(Ordering::Acquire), true); } + #[nightly_only_test] #[test] fn handles_recoverable_parse_error_in_non_ignored_file() { - if !is_nightly_channel!() { - return; - } let num_emitted_errors = Lrc::new(AtomicU32::new(0)); let can_reset_errors = Lrc::new(AtomicBool::new(false)); let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); @@ -424,11 +421,9 @@ mod tests { assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } + #[nightly_only_test] #[test] fn handles_mix_of_recoverable_parse_error() { - if !is_nightly_channel!() { - return; - } let num_emitted_errors = Lrc::new(AtomicU32::new(0)); let can_reset_errors = Lrc::new(AtomicBool::new(false)); let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); diff --git a/src/test/mod.rs b/src/test/mod.rs index e2620508c340b..cceb28dfea6d7 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -15,6 +15,8 @@ use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChu use crate::source_file; use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session}; +use rustfmt_config_proc_macro::nightly_only_test; + mod configuration_snippet; mod mod_resolver; mod parser; @@ -307,14 +309,11 @@ fn assert_output(source: &Path, expected_filename: &Path) { // Idempotence tests. Files in tests/target are checked to be unaltered by // rustfmt. +#[nightly_only_test] #[test] fn idempotence_tests() { init_log(); run_test_with(&TestSetting::default(), || { - // these tests require nightly - if !is_nightly_channel!() { - return; - } // Get all files in the tests/target directory. let files = get_test_files(Path::new("tests/target"), true); let (_reports, count, fails) = check_files(files, &None); @@ -332,13 +331,11 @@ fn idempotence_tests() { // Run rustfmt on itself. This operation must be idempotent. We also check that // no warnings are emitted. +// Issue-3443: these tests require nightly +#[nightly_only_test] #[test] fn self_tests() { init_log(); - // Issue-3443: these tests require nightly - if !is_nightly_channel!() { - return; - } let mut files = get_test_files(Path::new("tests"), false); let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"]; for dir in bin_directories { From 0fc846f979bc20d556cc07177b384094a421c54c Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Sun, 28 Nov 2021 15:22:49 -0600 Subject: [PATCH 14/16] refactor: maintain more AST info when formatting a RHS --- src/expr.rs | 57 +++++++++++++++++++++++++++++++++++++++++++-------- src/items.rs | 38 +++++++++++++++++++++++++++------- src/macros.rs | 5 +++-- src/types.rs | 5 +++-- 4 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 58942e442de05..5fd86c1a4eadd 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -196,9 +196,10 @@ pub(crate) fn format_expr( capture, is_async, movability, fn_decl, body, expr.span, context, shape, ) } - ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => { - rewrite_chain(expr, context, shape) - } + ast::ExprKind::Try(..) + | ast::ExprKind::Field(..) + | ast::ExprKind::MethodCall(..) + | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| { wrap_str( @@ -377,7 +378,6 @@ pub(crate) fn format_expr( )) } } - ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape), ast::ExprKind::Underscore => Some("_".to_owned()), ast::ExprKind::Err => None, }; @@ -829,6 +829,7 @@ impl<'a> ControlFlow<'a> { &format!("{}{}{}", matcher, pat_string, self.connector), expr, cond_shape, + &RhsAssignKind::Expr(&expr.kind, expr.span), RhsTactics::Default, comments_span, true, @@ -1839,6 +1840,34 @@ fn rewrite_unary_op( rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape) } +pub(crate) enum RhsAssignKind<'ast> { + Expr(&'ast ast::ExprKind, Span), + Bounds, + Ty, +} + +impl<'ast> RhsAssignKind<'ast> { + // TODO(calebcartwright) + // Preemptive addition for handling RHS with chains, not yet utilized. + // It may make more sense to construct the chain first and then check + // whether there are actually chain elements. + #[allow(dead_code)] + fn is_chain(&self) -> bool { + match self { + RhsAssignKind::Expr(kind, _) => { + matches!( + kind, + ast::ExprKind::Try(..) + | ast::ExprKind::Field(..) + | ast::ExprKind::MethodCall(..) + | ast::ExprKind::Await(_) + ) + } + _ => false, + } + } +} + fn rewrite_assignment( context: &RewriteContext<'_>, lhs: &ast::Expr, @@ -1855,7 +1884,13 @@ fn rewrite_assignment( let lhs_shape = shape.sub_width(operator_str.len() + 1)?; let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str); - rewrite_assign_rhs(context, lhs_str, rhs, shape) + rewrite_assign_rhs( + context, + lhs_str, + rhs, + &RhsAssignKind::Expr(&rhs.kind, rhs.span), + shape, + ) } /// Controls where to put the rhs. @@ -1876,9 +1911,10 @@ pub(crate) fn rewrite_assign_rhs, R: Rewrite>( context: &RewriteContext<'_>, lhs: S, ex: &R, + rhs_kind: &RhsAssignKind<'_>, shape: Shape, ) -> Option { - rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default) + rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default) } pub(crate) fn rewrite_assign_rhs_expr( @@ -1886,6 +1922,7 @@ pub(crate) fn rewrite_assign_rhs_expr( lhs: &str, ex: &R, shape: Shape, + rhs_kind: &RhsAssignKind<'_>, rhs_tactics: RhsTactics, ) -> Option { let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') { @@ -1910,6 +1947,7 @@ pub(crate) fn rewrite_assign_rhs_expr( ex, orig_shape, ex.rewrite(context, orig_shape), + rhs_kind, rhs_tactics, has_rhs_comment, ) @@ -1920,10 +1958,11 @@ pub(crate) fn rewrite_assign_rhs_with, R: Rewrite>( lhs: S, ex: &R, shape: Shape, + rhs_kind: &RhsAssignKind<'_>, rhs_tactics: RhsTactics, ) -> Option { let lhs = lhs.into(); - let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?; + let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?; Some(lhs + &rhs) } @@ -1932,6 +1971,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments, R: Rewrite>( lhs: S, ex: &R, shape: Shape, + rhs_kind: &RhsAssignKind<'_>, rhs_tactics: RhsTactics, between_span: Span, allow_extend: bool, @@ -1943,7 +1983,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments, R: Rewrite>( } else { shape }; - let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?; + let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?; if contains_comment { let rhs = rhs.trim_start(); @@ -1958,6 +1998,7 @@ fn choose_rhs( expr: &R, shape: Shape, orig_rhs: Option, + _rhs_kind: &RhsAssignKind<'_>, rhs_tactics: RhsTactics, has_rhs_comment: bool, ) -> Option { diff --git a/src/items.rs b/src/items.rs index 63c32e012df7f..3fe827ce696d4 100644 --- a/src/items.rs +++ b/src/items.rs @@ -18,7 +18,7 @@ use crate::config::lists::*; use crate::config::{BraceStyle, Config, IndentStyle, Version}; use crate::expr::{ is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with, - rewrite_assign_rhs_with_comments, RhsTactics, + rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics, }; use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}; use crate::macros::{rewrite_macro, MacroPosition}; @@ -116,7 +116,13 @@ impl Rewrite for ast::Local { // 1 = trailing semicolon; let nested_shape = shape.sub_width(1)?; - result = rewrite_assign_rhs(context, result, init, nested_shape)?; + result = rewrite_assign_rhs( + context, + result, + init, + &RhsAssignKind::Expr(&init.kind, init.span), + nested_shape, + )?; // todo else } @@ -564,11 +570,13 @@ impl<'a> FmtVisitor<'a> { let variant_body = if let Some(ref expr) = field.disr_expr { let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to); + let ex = &*expr.value; rewrite_assign_rhs_with( &context, lhs, - &*expr.value, + ex, shape, + &RhsAssignKind::Expr(&ex.kind, ex.span), RhsTactics::AllowOverflow, )? } else { @@ -1033,6 +1041,7 @@ pub(crate) fn format_trait( result + ":", bounds, shape, + &RhsAssignKind::Bounds, RhsTactics::ForceNextLineWithoutIndent, )?; } @@ -1213,7 +1222,14 @@ pub(crate) fn format_trait_alias( generic_bounds, generics, }; - rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";") + rewrite_assign_rhs( + context, + lhs, + &trait_alias_bounds, + &RhsAssignKind::Bounds, + shape.sub_width(1)?, + ) + .map(|s| s + ";") } fn format_unit_struct( @@ -1630,7 +1646,7 @@ fn rewrite_ty( // 1 = `;` let shape = Shape::indented(indent, context.config).sub_width(1)?; - rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";") + rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";") } else { Some(format!("{};", result)) } @@ -1720,7 +1736,7 @@ pub(crate) fn rewrite_struct_field( let is_prefix_empty = prefix.is_empty(); // We must use multiline. We are going to put attributes and a field on different lines. - let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?; + let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?; // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct. let field_str = if is_prefix_empty { field_str.trim_start() @@ -1850,6 +1866,7 @@ fn rewrite_static( &lhs, &**expr, Shape::legacy(remaining_width, offset.block_only()), + &RhsAssignKind::Expr(&expr.kind, expr.span), RhsTactics::Default, comments_span, true, @@ -3147,7 +3164,14 @@ impl Rewrite for ast::ForeignItem { rewrite_ident(context, self.ident) ); // 1 = ; - rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";") + rewrite_assign_rhs( + context, + prefix, + &**ty, + &RhsAssignKind::Ty, + shape.sub_width(1)?, + ) + .map(|s| s + ";") } ast::ForeignItemKind::TyAlias(ref ty_alias) => { let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span); diff --git a/src/macros.rs b/src/macros.rs index ef747638e33ec..a52568be9eac4 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -27,7 +27,7 @@ use crate::comment::{ contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses, }; use crate::config::lists::*; -use crate::expr::rewrite_array; +use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind}; use crate::lists::{itemize_list, write_list, ListFormatting}; use crate::overflow; use crate::rewrite::{Rewrite, RewriteContext}; @@ -1468,10 +1468,11 @@ fn format_lazy_static( id, ty.rewrite(context, nested_shape)? )); - result.push_str(&crate::expr::rewrite_assign_rhs( + result.push_str(&rewrite_assign_rhs( context, stmt, &*expr, + &RhsAssignKind::Expr(&expr.kind, expr.span), nested_shape.sub_width(1)?, )?); result.push(';'); diff --git a/src/types.rs b/src/types.rs index 891609783b61b..88f5dc4324510 100644 --- a/src/types.rs +++ b/src/types.rs @@ -10,6 +10,7 @@ use crate::config::lists::*; use crate::config::{IndentStyle, TypeDensity, Version}; use crate::expr::{ format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType, + RhsAssignKind, }; use crate::lists::{ definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator, @@ -430,7 +431,7 @@ impl Rewrite for ast::WherePredicate { format!("{}{}", type_str, colon) }; - rewrite_assign_rhs(context, lhs, bounds, shape)? + rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)? } ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { ref lifetime, @@ -443,7 +444,7 @@ impl Rewrite for ast::WherePredicate { .. }) => { let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?; - rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)? + rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)? } }; From 1f28683ffacebc91b3bc47b94c56690633226ff9 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Sun, 28 Nov 2021 23:39:31 -0500 Subject: [PATCH 15/16] Update nightly only test with #[nightly_only_test] attribute --- src/ignore_path.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/ignore_path.rs b/src/ignore_path.rs index d8974e12b8f5f..7738eee0a7604 100644 --- a/src/ignore_path.rs +++ b/src/ignore_path.rs @@ -37,21 +37,17 @@ mod test { use crate::config::{Config, FileName}; use crate::ignore_path::IgnorePathSet; + use rustfmt_config_proc_macro::nightly_only_test; + + #[nightly_only_test] #[test] fn test_ignore_path_set() { - match option_env!("CFG_RELEASE_CHANNEL") { - // this test requires nightly - None | Some("nightly") => { - let config = - Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")) - .unwrap(); - let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap(); - - assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs")))); - assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs")))); - assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs")))); - } - _ => (), - }; + let config = + Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")).unwrap(); + let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap(); + + assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs")))); + assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs")))); + assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs")))); } } From ec46ffd981d3d50572f1ad3f6033a7c33d27033f Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Fri, 19 Nov 2021 18:52:52 -0500 Subject: [PATCH 16/16] Determine when new comment lines are needed for itemized blocks Fixes 5088 Previously, rustfmt would add a new comment line anytime it reformatted an itemized block within a comment when ``wrap_comments=true``. This would lead to rustfmt adding empty comments with trailing whitespace. Now, new comment lines are only added if the original comment spanned multiple lines, if the comment needs to be wrapped, or if the comment originally started with an empty comment line. --- src/comment.rs | 43 +++++++++++++--- ..._nested_long_comment_wrap_comments_true.rs | 33 +++++++++++++ ..._long_itemized_block_wrap_comments_true.rs | 19 +++++++ .../very_long_comment_wrap_comments_true.rs | 13 +++++ ...nested_long_comment_wrap_comments_false.rs | 33 +++++++++++++ ..._nested_long_comment_wrap_comments_true.rs | 49 +++++++++++++++++++ ...line_itemized_block_wrap_comments_false.rs | 17 +++++++ ..._line_itemized_block_wrap_comments_true.rs | 17 +++++++ ...with_itemized_block_wrap_comments_false.rs | 37 ++++++++++++++ ..._with_itemized_block_wrap_comments_true.rs | 37 ++++++++++++++ ...line_itemized_block_wrap_comments_false.rs | 9 ++++ ..._line_itemized_block_wrap_comments_true.rs | 9 ++++ ...long_itemized_block_wrap_comments_false.rs | 19 +++++++ ..._long_itemized_block_wrap_comments_true.rs | 27 ++++++++++ ..._with_empty_comment_wrap_comments_false.rs | 17 +++++++ ...t_with_empty_comment_wrap_comments_true.rs | 17 +++++++ .../very_long_comment_wrap_comments_false.rs | 13 +++++ .../very_long_comment_wrap_comments_true.rs | 21 ++++++++ 18 files changed, 424 insertions(+), 6 deletions(-) create mode 100644 tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs create mode 100644 tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs create mode 100644 tests/source/issue-5088/very_long_comment_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs create mode 100644 tests/target/issue-5088/very_long_comment_wrap_comments_false.rs create mode 100644 tests/target/issue-5088/very_long_comment_wrap_comments_true.rs diff --git a/src/comment.rs b/src/comment.rs index 830d2b50aad82..0f850b9b2f2fb 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -519,6 +519,7 @@ struct CommentRewrite<'a> { opener: String, closer: String, line_start: String, + style: CommentStyle<'a>, } impl<'a> CommentRewrite<'a> { @@ -528,10 +529,14 @@ impl<'a> CommentRewrite<'a> { shape: Shape, config: &'a Config, ) -> CommentRewrite<'a> { - let (opener, closer, line_start) = if block_style { - CommentStyle::SingleBullet.to_str_tuplet() + let ((opener, closer, line_start), style) = if block_style { + ( + CommentStyle::SingleBullet.to_str_tuplet(), + CommentStyle::SingleBullet, + ) } else { - comment_style(orig, config.normalize_comments()).to_str_tuplet() + let style = comment_style(orig, config.normalize_comments()); + (style.to_str_tuplet(), style) }; let max_width = shape @@ -564,6 +569,7 @@ impl<'a> CommentRewrite<'a> { opener: opener.to_owned(), closer: closer.to_owned(), line_start: line_start.to_owned(), + style, }; cr.result.push_str(opener); cr @@ -583,6 +589,15 @@ impl<'a> CommentRewrite<'a> { result } + /// Check if any characters were written to the result buffer after the start of the comment. + /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening + /// characters for the comment. + fn buffer_contains_comment(&self) -> bool { + // if self.result.len() < self.opener.len() then an empty comment is in the buffer + // if self.result.len() > self.opener.len() then a non empty comment is in the buffer + self.result.len() != self.opener.len() + } + fn finish(mut self) -> String { if !self.code_block_buffer.is_empty() { // There is a code block that is not properly enclosed by backticks. @@ -598,7 +613,12 @@ impl<'a> CommentRewrite<'a> { // the last few lines are part of an itemized block self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent); let item_fmt = ib.create_string_format(&self.fmt); - self.result.push_str(&self.comment_line_separator); + + // only push a comment_line_separator for ItemizedBlocks if the comment is not empty + if self.buffer_contains_comment() { + self.result.push_str(&self.comment_line_separator); + } + self.result.push_str(&ib.opener); match rewrite_string( &ib.trimmed_block_as_string(), @@ -632,7 +652,13 @@ impl<'a> CommentRewrite<'a> { line: &'a str, has_leading_whitespace: bool, ) -> bool { - let is_last = i == count_newlines(orig); + let num_newlines = count_newlines(orig); + let is_last = i == num_newlines; + let needs_new_comment_line = if self.style.is_block_comment() { + num_newlines > 0 || self.buffer_contains_comment() + } else { + self.buffer_contains_comment() + }; if let Some(ref mut ib) = self.item_block { if ib.add_line(line) { @@ -641,7 +667,12 @@ impl<'a> CommentRewrite<'a> { self.is_prev_line_multi_line = false; self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent); let item_fmt = ib.create_string_format(&self.fmt); - self.result.push_str(&self.comment_line_separator); + + // only push a comment_line_separator if we need to start a new comment line + if needs_new_comment_line { + self.result.push_str(&self.comment_line_separator); + } + self.result.push_str(&ib.opener); match rewrite_string( &ib.trimmed_block_as_string(), diff --git a/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs b/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs new file mode 100644 index 0000000000000..09f68cae42406 --- /dev/null +++ b/tests/source/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs @@ -0,0 +1,33 @@ +// rustfmt-wrap_comments: true + +fn main() { + { + { + { + { + { + { + { + { + { + { + { + // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc + + // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc + + /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */ + + /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */ + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs b/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs new file mode 100644 index 0000000000000..75f748000f9ba --- /dev/null +++ b/tests/source/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs @@ -0,0 +1,19 @@ +// rustfmt-wrap_comments: true + +// +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +// +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +/* + * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* + * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ + +/* + * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* + * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ diff --git a/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs b/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs new file mode 100644 index 0000000000000..00437f00216ba --- /dev/null +++ b/tests/source/issue-5088/very_long_comment_wrap_comments_true.rs @@ -0,0 +1,13 @@ +// rustfmt-wrap_comments: true + +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ + +/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ diff --git a/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs b/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs new file mode 100644 index 0000000000000..f4801de018481 --- /dev/null +++ b/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_false.rs @@ -0,0 +1,33 @@ +// rustfmt-wrap_comments: false + +fn main() { + { + { + { + { + { + { + { + { + { + { + { + // - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc + + // * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc + + /* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */ + + /* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */ + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs b/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs new file mode 100644 index 0000000000000..b289c9f859e0e --- /dev/null +++ b/tests/target/issue-5088/deeply_nested_long_comment_wrap_comments_true.rs @@ -0,0 +1,49 @@ +// rustfmt-wrap_comments: true + +fn main() { + { + { + { + { + { + { + { + { + { + { + { + // - aaaa aaaaaaaaa aaaaaaaaa + // aaaaaaaaa aaaaaaaaa + // bbbbbbbbbb bbbbbbbbb + // bbbbbbbbb ccc cccccccccc + // ccccccc cccccccc + + // * aaaa aaaaaaaaa aaaaaaaaa + // aaaaaaaaa aaaaaaaaa + // bbbbbbbbbb bbbbbbbbb + // bbbbbbbbb ccc cccccccccc + // ccccccc cccccccc + + /* - aaaa aaaaaaaaa aaaaaaaaa + * aaaaaaaaa aaaaaaaaa + * bbbbbbbbbb bbbbbbbbb + * bbbbbbbbb ccc cccccccccc + * ccccccc cccccccc */ + + /* * aaaa aaaaaaaaa aaaaaaaaa + * aaaaaaaaa aaaaaaaaa + * bbbbbbbbbb bbbbbbbbb + * bbbbbbbbb ccc cccccccccc + * ccccccc cccccccc */ + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs b/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs new file mode 100644 index 0000000000000..60beed1b04828 --- /dev/null +++ b/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_false.rs @@ -0,0 +1,17 @@ +// rustfmt-wrap_comments: false + +// - some itemized block 1 +// - some itemized block 2 + +// * some itemized block 3 +// * some itemized block 4 + +/* + * - some itemized block 5 + * - some itemized block 6 + */ + +/* + * * some itemized block 7 + * * some itemized block 8 + */ diff --git a/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs b/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs new file mode 100644 index 0000000000000..84fba4b7c1986 --- /dev/null +++ b/tests/target/issue-5088/multi_line_itemized_block_wrap_comments_true.rs @@ -0,0 +1,17 @@ +// rustfmt-wrap_comments: true + +// - some itemized block 1 +// - some itemized block 2 + +// * some itemized block 3 +// * some itemized block 4 + +/* + * - some itemized block 5 + * - some itemized block 6 + */ + +/* + * * some itemized block 7 + * * some itemized block 8 + */ diff --git a/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs b/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs new file mode 100644 index 0000000000000..d1bf44f6c7413 --- /dev/null +++ b/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_false.rs @@ -0,0 +1,37 @@ +// rustfmt-wrap_comments: false + +// Some text +// - some itemized block 1 +// - some itemized block 2 +// Some more text +// - some itemized block 3 +// - some itemized block 4 +// Even more text + +// Some text +// * some itemized block 5 +// * some itemized block 6 +// Some more text +// * some itemized block 7 +// * some itemized block 8 +// Even more text + +/* + * Some text + * - some itemized block 9 + * - some itemized block 10 + * Some more text + * - some itemized block 11 + * - some itemized block 12 + * Even more text + */ + +/* + * Some text + * * some itemized block 13 + * * some itemized block 14 + * Some more text + * * some itemized block 15 + * * some itemized block 16 + * Even more text + */ diff --git a/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs b/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs new file mode 100644 index 0000000000000..f767491f902d4 --- /dev/null +++ b/tests/target/issue-5088/multi_line_text_with_itemized_block_wrap_comments_true.rs @@ -0,0 +1,37 @@ +// rustfmt-wrap_comments: true + +// Some text +// - some itemized block 1 +// - some itemized block 2 +// Some more text +// - some itemized block 3 +// - some itemized block 4 +// Even more text + +// Some text +// * some itemized block 5 +// * some itemized block 6 +// Some more text +// * some itemized block 7 +// * some itemized block 8 +// Even more text + +/* + * Some text + * - some itemized block 9 + * - some itemized block 10 + * Some more text + * - some itemized block 11 + * - some itemized block 12 + * Even more text + */ + +/* + * Some text + * * some itemized block 13 + * * some itemized block 14 + * Some more text + * * some itemized block 15 + * * some itemized block 16 + * Even more text + */ diff --git a/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs b/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs new file mode 100644 index 0000000000000..2cd85c787f974 --- /dev/null +++ b/tests/target/issue-5088/single_line_itemized_block_wrap_comments_false.rs @@ -0,0 +1,9 @@ +// rustfmt-wrap_comments: false + +// - some itemized block 1 + +// * some itemized block 2 + +/* - some itemized block 3 */ + +/* * some itemized block 4 */ diff --git a/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs b/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs new file mode 100644 index 0000000000000..e9f343d75d5eb --- /dev/null +++ b/tests/target/issue-5088/single_line_itemized_block_wrap_comments_true.rs @@ -0,0 +1,9 @@ +// rustfmt-wrap_comments: true + +// - some itemized block 1 + +// * some itemized block 2 + +/* - some itemized block 3 */ + +/* * some itemized block 4 */ diff --git a/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs b/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs new file mode 100644 index 0000000000000..97bb7733d189f --- /dev/null +++ b/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_false.rs @@ -0,0 +1,19 @@ +// rustfmt-wrap_comments: false + +// +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +// +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +/* + * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* + * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ + +/* + * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* + * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ diff --git a/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs b/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs new file mode 100644 index 0000000000000..c8af8383e058a --- /dev/null +++ b/tests/target/issue-5088/start_with_empty_comment_very_long_itemized_block_wrap_comments_true.rs @@ -0,0 +1,27 @@ +// rustfmt-wrap_comments: true + +// +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. + +// +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. + +/* + * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ +/* + * - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ + +/* + * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ +/* + * * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ diff --git a/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs b/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs new file mode 100644 index 0000000000000..75cc42c0e66bb --- /dev/null +++ b/tests/target/issue-5088/start_with_empty_comment_wrap_comments_false.rs @@ -0,0 +1,17 @@ +// rustfmt-wrap_comments: false + +// +// - some itemized block 1 +// - some itemized block 2 + +// +// * some itemized block 3 +// * some itemized block 4 + +/* + * - some itemized block 5 + * - some itemized block 6 */ + +/* + * * some itemized block 7 + * * some itemized block 8 */ diff --git a/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs b/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs new file mode 100644 index 0000000000000..ef2c8f90cd309 --- /dev/null +++ b/tests/target/issue-5088/start_with_empty_comment_wrap_comments_true.rs @@ -0,0 +1,17 @@ +// rustfmt-wrap_comments: true + +// +// - some itemized block 1 +// - some itemized block 2 + +// +// * some itemized block 3 +// * some itemized block 4 + +/* + * - some itemized block 5 + * - some itemized block 6 */ + +/* + * * some itemized block 7 + * * some itemized block 8 */ diff --git a/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs b/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs new file mode 100644 index 0000000000000..c826cc5d4da6e --- /dev/null +++ b/tests/target/issue-5088/very_long_comment_wrap_comments_false.rs @@ -0,0 +1,13 @@ +// rustfmt-wrap_comments: false + +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + +/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ + +/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ +/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/ diff --git a/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs b/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs new file mode 100644 index 0000000000000..7f764dbd8a22b --- /dev/null +++ b/tests/target/issue-5088/very_long_comment_wrap_comments_true.rs @@ -0,0 +1,21 @@ +// rustfmt-wrap_comments: true + +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. +// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. + +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. +// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod +// tempor incididunt ut labore et dolore magna aliqua. + +/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ +/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ + +/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */ +/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + * tempor incididunt ut labore et dolore magna aliqua. */