Merge remote-tracking branch 'upstream/master' into subtree-sync-2023-01-24

This commit is contained in:
Caleb Cartwright 2023-01-23 21:19:31 -06:00
commit e7d87ad61d
109 changed files with 2561 additions and 185 deletions

33
.github/workflows/check_diff.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: Diff Check
on:
workflow_dispatch:
inputs:
clone_url:
description: 'Git url of a rustfmt fork to compare against the latest master rustfmt'
required: true
branch_name:
description: 'Name of the feature branch on the forked repo'
required: true
commit_hash:
description: 'Optional commit hash from the feature branch'
required: false
rustfmt_configs:
description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch'
required: false
jobs:
diff_check:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v3
- 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: check diff
run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }}

View File

@ -27,7 +27,6 @@ jobs:
tempdir, tempdir,
futures-rs, futures-rs,
rust-clippy, rust-clippy,
failure,
] ]
include: include:
# Allowed Failures # Allowed Failures
@ -63,9 +62,6 @@ jobs:
# Original comment was: temporal build failure due to breaking changes in the nightly compiler # Original comment was: temporal build failure due to breaking changes in the nightly compiler
- integration: rust-semverver - integration: rust-semverver
allow-failure: true allow-failure: true
# Can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged
- integration: failure
allow-failure: true
steps: steps:
- name: checkout - name: checkout

View File

@ -840,7 +840,7 @@ from formatting an attribute #3665
- Fix formatting of raw string literals #2983 - Fix formatting of raw string literals #2983
- Handle chain with try operators with spaces #2986 - Handle chain with try operators with spaces #2986
- Use correct shape in Visual tuple rewriting #2987 - Use correct shape in Visual tuple rewriting #2987
- Impove formatting of arguments with `visual_style = "Visual"` option #2988 - Improve formatting of arguments with `visual_style = "Visual"` option #2988
- Change `print_diff` to output the correct line number 992b179 - Change `print_diff` to output the correct line number 992b179
- Propagate errors about failing to rewrite a macro 6f318e3 - Propagate errors about failing to rewrite a macro 6f318e3
- Handle formatting of long function signature #3010 - Handle formatting of long function signature #3010

2
Cargo.lock generated
View File

@ -476,7 +476,7 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
[[package]] [[package]]
name = "rustfmt-config_proc_macro" name = "rustfmt-config_proc_macro"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -57,7 +57,7 @@ unicode-segmentation = "1.9"
unicode-width = "0.1" unicode-width = "0.1"
unicode_categories = "0.1" unicode_categories = "0.1"
rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" } rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" }
# A noop dependency that changes in the Rust repository, it's a bit of a hack. # A noop dependency that changes in the Rust repository, it's a bit of a hack.
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`

View File

@ -1,6 +1,6 @@
# Configuring Rustfmt # Configuring Rustfmt
Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/1.0.4/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this: A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this:
@ -425,7 +425,7 @@ fn example() {
## `comment_width` ## `comment_width`
Maximum length of comments. No effect unless`wrap_comments = true`. Maximum length of comments. No effect unless `wrap_comments = true`.
- **Default value**: `80` - **Default value**: `80`
- **Possible values**: any positive integer - **Possible values**: any positive integer
@ -589,7 +589,7 @@ doesn't get ignored when aligning.
#### `0` (default): #### `0` (default):
```rust ```rust
enum Bar { enum Foo {
A = 0, A = 0,
Bb = 1, Bb = 1,
RandomLongVariantGoesHere = 10, RandomLongVariantGoesHere = 10,
@ -645,7 +645,8 @@ trailing whitespaces.
## `fn_args_layout` ## `fn_args_layout`
Control the layout of arguments in a function This option is deprecated and has been renamed to `fn_params_layout` to better communicate that
it affects the layout of parameters in function signatures.
- **Default value**: `"Tall"` - **Default value**: `"Tall"`
- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` - **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"`
@ -753,6 +754,8 @@ trait Lorem {
} }
``` ```
See also [`fn_params_layout`](#fn_params_layout)
## `fn_call_width` ## `fn_call_width`
Maximum width of the args of a function call before falling back to vertical formatting. Maximum width of the args of a function call before falling back to vertical formatting.
@ -765,6 +768,117 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi
See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
## `fn_params_layout`
Control the layout of parameters in function signatures.
- **Default value**: `"Tall"`
- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"`
- **Stable**: Yes
#### `"Tall"` (default):
```rust
trait Lorem {
fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
// body
}
fn lorem(
ipsum: Ipsum,
dolor: Dolor,
sit: Sit,
amet: Amet,
consectetur: Consectetur,
adipiscing: Adipiscing,
elit: Elit,
);
fn lorem(
ipsum: Ipsum,
dolor: Dolor,
sit: Sit,
amet: Amet,
consectetur: Consectetur,
adipiscing: Adipiscing,
elit: Elit,
) {
// body
}
}
```
#### `"Compressed"`:
```rust
trait Lorem {
fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
// body
}
fn lorem(
ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
adipiscing: Adipiscing, elit: Elit,
);
fn lorem(
ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
adipiscing: Adipiscing, elit: Elit,
) {
// body
}
}
```
#### `"Vertical"`:
```rust
trait Lorem {
fn lorem(
ipsum: Ipsum,
dolor: Dolor,
sit: Sit,
amet: Amet,
);
fn lorem(
ipsum: Ipsum,
dolor: Dolor,
sit: Sit,
amet: Amet,
) {
// body
}
fn lorem(
ipsum: Ipsum,
dolor: Dolor,
sit: Sit,
amet: Amet,
consectetur: Consectetur,
adipiscing: Adipiscing,
elit: Elit,
);
fn lorem(
ipsum: Ipsum,
dolor: Dolor,
sit: Sit,
amet: Amet,
consectetur: Consectetur,
adipiscing: Adipiscing,
elit: Elit,
) {
// body
}
}
```
## `fn_single_line` ## `fn_single_line`
Put single-expression functions on a single line Put single-expression functions on a single line
@ -1014,6 +1128,62 @@ macro_rules! foo {
See also [`format_macro_matchers`](#format_macro_matchers). See also [`format_macro_matchers`](#format_macro_matchers).
## `skip_macro_invocations`
Skip formatting the bodies of macro invocations with the following names.
rustfmt will not format any macro invocation for macros with names set in this list.
Including the special value "*" will prevent any macro invocations from being formatted.
Note: This option does not have any impact on how rustfmt formats macro definitions.
- **Default value**: `[]`
- **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]`
- **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346))
#### `[]` (default):
rustfmt will follow its standard approach to formatting macro invocations.
No macro invocations will be skipped based on their name. More information about rustfmt's standard macro invocation formatting behavior can be found in [#5437](https://github.com/rust-lang/rustfmt/discussions/5437).
```rust
lorem!(
const _: u8 = 0;
);
ipsum!(
const _: u8 = 0;
);
```
#### `["lorem"]`:
The named macro invocations will be skipped.
```rust
lorem!(
const _: u8 = 0;
);
ipsum!(
const _: u8 = 0;
);
```
#### `["*"]`:
The special selector `*` will skip all macro invocations.
```rust
lorem!(
const _: u8 = 0;
);
ipsum!(
const _: u8 = 0;
);
```
## `format_strings` ## `format_strings`
@ -1687,13 +1857,16 @@ pub enum Foo {}
## `imports_granularity` ## `imports_granularity`
How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity. Controls how imports are structured in `use` statements. Imports will be merged or split to the configured level of granularity.
Similar to other `import` related configuration options, this option operates within the bounds of user-defined groups of imports. See [`group_imports`](#group_imports) for more information on import groups.
Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments.
- **Default value**: `Preserve` - **Default value**: `Preserve`
- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One` - **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
- **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991)) - **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments.
#### `Preserve` (default): #### `Preserve` (default):

View File

@ -2,7 +2,7 @@ This document outlines processes regarding management of rustfmt.
# Stabilising an Option # Stabilising an Option
In this Section, we describe how to stabilise an option of the rustfmt's configration. In this Section, we describe how to stabilise an option of the rustfmt's configuration.
## Conditions ## Conditions

View File

@ -1,4 +1,5 @@
set "RUSTFLAGS=-D warnings" set "RUSTFLAGS=-D warnings"
set "RUSTFMT_CI=1"
:: Print version information :: Print version information
rustc -Vv || exit /b 1 rustc -Vv || exit /b 1

View File

@ -3,6 +3,7 @@
set -euo pipefail set -euo pipefail
export RUSTFLAGS="-D warnings" export RUSTFLAGS="-D warnings"
export RUSTFMT_CI=1
# Print version information # Print version information
rustc -Vv rustc -Vv

199
ci/check_diff.sh Executable file
View File

@ -0,0 +1,199 @@
#!/bin/bash
function print_usage() {
echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
}
if [ $# -le 1 ]; then
print_usage
exit 1
fi
REMOTE_REPO=$1
FEATURE_BRANCH=$2
OPTIONAL_COMMIT_HASH=$3
OPTIONAL_RUSTFMT_CONFIGS=$4
# OUTPUT array used to collect all the status of running diffs on various repos
STATUSES=()
# Clone a git repository and cd into it.
#
# Parameters:
# $1: git clone url
# $2: directory where the repo should be cloned
function clone_repo() {
GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2
}
# Initialize Git submoduels for the repo.
#
# Parameters
# $1: list of directories to initialize
function init_submodules() {
git submodule update --init $1
}
# Run rusfmt with the --check flag to see if a diff is produced.
#
# Parameters:
# $1: Path to a rustfmt binary
# $2: Output file path for the diff
# $3: Any additional configuration options to pass to rustfmt
#
# Globlas:
# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
function create_diff() {
local config;
if [ -z "$3" ]; then
config="--config=error_on_line_overflow=false,error_on_unformatted=false"
else
config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS"
fi
for i in `find . | grep "\.rs$"`
do
$1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null
done
}
# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs
#
# Parameters
# $1: Name of the repository (used for logging)
#
# Globlas:
# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt`
# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt`
# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
function check_diff() {
echo "running rustfmt (master) on $1"
create_diff $RUSFMT_BIN rustfmt_diff.txt
echo "running rustfmt (feature) on $1"
create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS
echo "checking diff"
local diff;
# we don't add color to the diff since we added color when running rustfmt --check.
# tail -n + 6 removes the git diff header info
# cut -c 2- removes the leading diff characters("+","-"," ") from running git diff.
# Again, the diff output we care about was already added when we ran rustfmt --check
diff=$(
git --no-pager diff --color=never \
--unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2-
)
if [ -z "$diff" ]; then
echo "no diff detected between rustfmt and the feture branch"
return 0
else
echo "$diff"
return 1
fi
}
# Compiles and produces two rustfmt binaries.
# One for the current master, and another for the feature branch
#
# Parameters:
# $1: Directory where rustfmt will be cloned
#
# Globlas:
# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
# $FEATURE_BRANCH: Name of the feature branch
# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
function compile_rustfmt() {
RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git"
clone_repo $RUSTFMT_REPO $1
git remote add feature $REMOTE_REPO
git fetch feature $FEATURE_BRANCH
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
git switch $FEATURE_BRANCH
else
git switch $OPTIONAL_COMMIT_HASH --detach
fi
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
RUSFMT_BIN=$1/rustfmt
FEATURE_BIN=$1/feature_rustfmt
}
# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
#
# Parameters
# $1: Clone URL for the repo
# $2: Name of the repo (mostly used for logging)
# $3: Path to any submodules that should be initialized
function check_repo() {
WORKDIR=$(pwd)
REPO_URL=$1
REPO_NAME=$2
SUBMODULES=$3
local tmp_dir;
tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX)
clone_repo $REPO_URL $tmp_dir
if [ ! -z "$SUBMODULES" ]; then
init_submodules $SUBMODULES
fi
check_diff $REPO_NAME
# append the status of running `check_diff` to the STATUSES array
STATUSES+=($?)
echo "removing tmp_dir $tmp_dir"
rm -rf $tmp_dir
cd $WORKDIR
}
function main() {
tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX)
echo Created tmp_dir $tmp_dir
compile_rustfmt $tmp_dir
# run checks
check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust
check_repo "https://github.com/rust-lang/cargo.git" cargo
check_repo "https://github.com/rust-lang/miri.git" miri
check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer
check_repo "https://github.com/bitflags/bitflags.git" bitflags
check_repo "https://github.com/rust-lang/log.git" log
check_repo "https://github.com/rust-lang/mdBook.git" mdBook
check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd
check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo
check_repo "https://github.com/Stebalien/tempfile.git" tempfile
check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs
check_repo "https://github.com/dtolnay/anyhow.git" anyhow
check_repo "https://github.com/dtolnay/thiserror.git" thiserror
check_repo "https://github.com/dtolnay/syn.git" syn
check_repo "https://github.com/serde-rs/serde.git" serde
check_repo "https://github.com/rust-lang/rustlings.git" rustlings
check_repo "https://github.com/rust-lang/rustup.git" rustup
check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket
check_repo "https://github.com/rustls/rustls.git" rustls
check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen
check_repo "https://github.com/hyperium/hyper.git" hyper
check_repo "https://github.com/actix/actix.git" actix
check_repo "https://github.com/denoland/deno.git" denoland_deno
# cleanup temp dir
echo removing tmp_dir $tmp_dir
rm -rf $tmp_dir
# figure out the exit code
for status in ${STATUSES[@]}
do
if [ $status -eq 1 ]; then
echo "formatting diff found 💔"
return 1
fi
done
echo "no diff found 😊"
}
main

View File

@ -91,14 +91,28 @@ case ${INTEGRATION} in
cd - cd -
;; ;;
crater) crater)
git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
cd ${INTEGRATION} cd ${INTEGRATION}
show_head show_head
check_fmt_with_lib_tests check_fmt_with_lib_tests
cd - cd -
;; ;;
bitflags)
git clone --depth=1 https://github.com/bitflags/${INTEGRATION}.git
cd ${INTEGRATION}
show_head
check_fmt_with_all_tests
cd -
;;
error-chain | tempdir)
git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git
cd ${INTEGRATION}
show_head
check_fmt_with_all_tests
cd -
;;
*) *)
git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
cd ${INTEGRATION} cd ${INTEGRATION}
show_head show_head
check_fmt_with_all_tests check_fmt_with_all_tests

View File

@ -22,7 +22,7 @@ dependencies = [
[[package]] [[package]]
name = "rustfmt-config_proc_macro" name = "rustfmt-config_proc_macro"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "rustfmt-config_proc_macro" name = "rustfmt-config_proc_macro"
version = "0.2.0" version = "0.3.0"
edition = "2018" edition = "2018"
description = "A collection of procedural macros for rustfmt" description = "A collection of procedural macros for rustfmt"
license = "Apache-2.0/MIT" license = "Apache-2.0/MIT"

View File

@ -1,8 +1,10 @@
//! This module provides utilities for handling attributes on variants //! This module provides utilities for handling attributes on variants
//! of `config_type` enum. Currently there are two types of attributes //! of `config_type` enum. Currently there are the following attributes
//! that could appear on the variants of `config_type` enum: `doc_hint` //! that could appear on the variants of `config_type` enum:
//! and `value`. Both comes in the form of name-value pair whose value //!
//! is string literal. //! - `doc_hint`: name-value pair whose value is string literal
//! - `value`: name-value pair whose value is string literal
//! - `unstable_variant`: name only
/// Returns the value of the first `doc_hint` attribute in the given slice or /// Returns the value of the first `doc_hint` attribute in the given slice or
/// `None` if `doc_hint` attribute is not available. /// `None` if `doc_hint` attribute is not available.
@ -27,6 +29,11 @@ pub fn find_config_value(attrs: &[syn::Attribute]) -> Option<String> {
attrs.iter().filter_map(config_value).next() attrs.iter().filter_map(config_value).next()
} }
/// Returns `true` if the there is at least one `unstable` attribute in the given slice.
pub fn any_unstable_variant(attrs: &[syn::Attribute]) -> bool {
attrs.iter().any(is_unstable_variant)
}
/// Returns a string literal value if the given attribute is `value` /// Returns a string literal value if the given attribute is `value`
/// attribute or `None` otherwise. /// attribute or `None` otherwise.
pub fn config_value(attr: &syn::Attribute) -> Option<String> { pub fn config_value(attr: &syn::Attribute) -> Option<String> {
@ -38,6 +45,11 @@ pub fn is_config_value(attr: &syn::Attribute) -> bool {
is_attr_name_value(attr, "value") is_attr_name_value(attr, "value")
} }
/// Returns `true` if the given attribute is an `unstable` attribute.
pub fn is_unstable_variant(attr: &syn::Attribute) -> bool {
is_attr_path(attr, "unstable_variant")
}
fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool { fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
attr.parse_meta().ok().map_or(false, |meta| match meta { attr.parse_meta().ok().map_or(false, |meta| match meta {
syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true, syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true,
@ -45,6 +57,13 @@ fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
}) })
} }
fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
attr.parse_meta().ok().map_or(false, |meta| match meta {
syn::Meta::Path(path) if path.is_ident(name) => true,
_ => false,
})
}
fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> { fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> {
attr.parse_meta().ok().and_then(|meta| match meta { attr.parse_meta().ok().and_then(|meta| match meta {
syn::Meta::NameValue(syn::MetaNameValue { syn::Meta::NameValue(syn::MetaNameValue {

View File

@ -1,5 +1,6 @@
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
use crate::attrs::*; use crate::attrs::*;
use crate::utils::*; use crate::utils::*;
@ -47,12 +48,23 @@ fn process_variant(variant: &syn::Variant) -> TokenStream {
let metas = variant let metas = variant
.attrs .attrs
.iter() .iter()
.filter(|attr| !is_doc_hint(attr) && !is_config_value(attr)); .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr) && !is_unstable_variant(attr));
let attrs = fold_quote(metas, |meta| quote!(#meta)); let attrs = fold_quote(metas, |meta| quote!(#meta));
let syn::Variant { ident, fields, .. } = variant; let syn::Variant { ident, fields, .. } = variant;
quote!(#attrs #ident #fields) quote!(#attrs #ident #fields)
} }
/// Return the correct syntax to pattern match on the enum variant, discarding all
/// internal field data.
fn fields_in_variant(variant: &syn::Variant) -> TokenStream {
// With thanks to https://stackoverflow.com/a/65182902
match &variant.fields {
syn::Fields::Unnamed(_) => quote_spanned! { variant.span() => (..) },
syn::Fields::Unit => quote_spanned! { variant.span() => },
syn::Fields::Named(_) => quote_spanned! { variant.span() => {..} },
}
}
fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream { fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
let doc_hint = variants let doc_hint = variants
.iter() .iter()
@ -60,12 +72,26 @@ fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("|"); .join("|");
let doc_hint = format!("[{}]", doc_hint); let doc_hint = format!("[{}]", doc_hint);
let variant_stables = variants
.iter()
.map(|v| (&v.ident, fields_in_variant(&v), !unstable_of_variant(v)));
let match_patterns = fold_quote(variant_stables, |(v, fields, stable)| {
quote! {
#ident::#v #fields => #stable,
}
});
quote! { quote! {
use crate::config::ConfigType; use crate::config::ConfigType;
impl ConfigType for #ident { impl ConfigType for #ident {
fn doc_hint() -> String { fn doc_hint() -> String {
#doc_hint.to_owned() #doc_hint.to_owned()
} }
fn stable_variant(&self) -> bool {
match self {
#match_patterns
}
}
} }
} }
} }
@ -123,13 +149,21 @@ fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream {
} }
fn doc_hint_of_variant(variant: &syn::Variant) -> String { fn doc_hint_of_variant(variant: &syn::Variant) -> String {
find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string()) let mut text = find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string());
if unstable_of_variant(&variant) {
text.push_str(" (unstable)")
};
text
} }
fn config_value_of_variant(variant: &syn::Variant) -> String { fn config_value_of_variant(variant: &syn::Variant) -> String {
find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string()) find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string())
} }
fn unstable_of_variant(variant: &syn::Variant) -> bool {
any_unstable_variant(&variant.attrs)
}
fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream { fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream {
let arms = fold_quote(variants.iter(), |v| { let arms = fold_quote(variants.iter(), |v| {
let v_ident = &v.ident; let v_ident = &v.ident;

View File

@ -69,3 +69,16 @@ pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
TokenStream::from_str("").unwrap() TokenStream::from_str("").unwrap()
} }
} }
/// Used to conditionally output the TokenStream for tests that should be run as part of rustfmts
/// test suite, but should be ignored when running in the rust-lang/rust test suite.
#[proc_macro_attribute]
pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStream {
if option_env!("RUSTFMT_CI").is_some() {
input
} else {
let mut token_stream = TokenStream::from_str("#[ignore]").unwrap();
token_stream.extend(input);
token_stream
}
}

View File

@ -1,6 +1,7 @@
pub mod config { pub mod config {
pub trait ConfigType: Sized { pub trait ConfigType: Sized {
fn doc_hint() -> String; fn doc_hint() -> String;
fn stable_variant(&self) -> bool;
} }
} }

View File

@ -1,3 +1,3 @@
[toolchain] [toolchain]
channel = "nightly-2022-06-21" channel = "nightly-2022-08-06"
components = ["rustc-dev"] components = ["rustc-dev"]

View File

@ -336,7 +336,7 @@ impl Rewrite for ast::Attribute {
} else { } else {
let should_skip = self let should_skip = self
.ident() .ident()
.map(|s| context.skip_context.skip_attribute(s.name.as_str())) .map(|s| context.skip_context.attributes.skip(s.name.as_str()))
.unwrap_or(false); .unwrap_or(false);
let prefix = attr_prefix(self); let prefix = attr_prefix(self);
@ -390,7 +390,7 @@ impl Rewrite for [ast::Attribute] {
// Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]` // Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]`
// or `#![rustfmt::skip::attributes(derive)]` // or `#![rustfmt::skip::attributes(derive)]`
let skip_derives = context.skip_context.skip_attribute("derive"); let skip_derives = context.skip_context.attributes.skip("derive");
// This is not just a simple map because we need to handle doc comments // This is not just a simple map because we need to handle doc comments
// (where we take as many doc comment attributes as possible) and possibly // (where we take as many doc comment attributes as possible) and possibly

View File

@ -136,7 +136,7 @@ fn make_opts() -> Options {
"l", "l",
"files-with-diff", "files-with-diff",
"Prints the names of mismatched files that were formatted. Prints the names of \ "Prints the names of mismatched files that were formatted. Prints the names of \
files that would be formated when used with `--check` mode. ", files that would be formatted when used with `--check` mode. ",
); );
opts.optmulti( opts.optmulti(
"", "",

View File

@ -198,12 +198,10 @@ fn convert_message_format_to_rustfmt_args(
Ok(()) Ok(())
} }
"human" => Ok(()), "human" => Ok(()),
_ => { _ => Err(format!(
return Err(format!(
"invalid --message-format value: {}. Allowed values are: short|json|human", "invalid --message-format value: {}. Allowed values are: short|json|human",
message_format message_format
)); )),
}
} }
} }
@ -215,7 +213,7 @@ fn print_usage_to_stderr(reason: &str) {
.expect("failed to write to stderr"); .expect("failed to write to stderr");
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Verbosity { pub enum Verbosity {
Verbose, Verbose,
Normal, Normal,

View File

@ -70,9 +70,9 @@ fn mandatory_separator() {
.is_err() .is_err()
); );
assert!( assert!(
!Opts::command() Opts::command()
.try_get_matches_from(&["test", "--", "--emit"]) .try_get_matches_from(&["test", "--", "--emit"])
.is_err() .is_ok()
); );
} }

View File

@ -70,10 +70,64 @@ use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape; use crate::shape::Shape;
use crate::source_map::SpanUtils; use crate::source_map::SpanUtils;
use crate::utils::{ use crate::utils::{
self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident, self, filtered_str_fits, first_line_width, last_line_extendable, last_line_width, mk_sp,
trimmed_last_line_width, wrap_str, rewrite_ident, trimmed_last_line_width, wrap_str,
}; };
/// Provides the original input contents from the span
/// of a chain element with trailing spaces trimmed.
fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option<String> {
context.snippet_provider.span_to_snippet(span).map(|s| {
s.lines()
.map(|l| l.trim_end())
.collect::<Vec<_>>()
.join("\n")
})
}
fn format_chain_item(
item: &ChainItem,
context: &RewriteContext<'_>,
rewrite_shape: Shape,
allow_overflow: bool,
) -> Option<String> {
if allow_overflow {
item.rewrite(context, rewrite_shape)
.or_else(|| format_overflow_style(item.span, context))
} else {
item.rewrite(context, rewrite_shape)
}
}
fn get_block_child_shape(
prev_ends_with_block: bool,
context: &RewriteContext<'_>,
shape: Shape,
) -> Shape {
if prev_ends_with_block {
shape.block_indent(0)
} else {
shape.block_indent(context.config.tab_spaces())
}
.with_max_width(context.config)
}
fn get_visual_style_child_shape(
context: &RewriteContext<'_>,
shape: Shape,
offset: usize,
parent_overflowing: bool,
) -> Option<Shape> {
if !parent_overflowing {
shape
.with_max_width(context.config)
.offset_left(offset)
.map(|s| s.visual_indent(0))
} else {
Some(shape.visual_indent(offset))
}
}
pub(crate) fn rewrite_chain( pub(crate) fn rewrite_chain(
expr: &ast::Expr, expr: &ast::Expr,
context: &RewriteContext<'_>, context: &RewriteContext<'_>,
@ -496,6 +550,8 @@ struct ChainFormatterShared<'a> {
// The number of children in the chain. This is not equal to `self.children.len()` // The number of children in the chain. This is not equal to `self.children.len()`
// because `self.children` will change size as we process the chain. // because `self.children` will change size as we process the chain.
child_count: usize, child_count: usize,
// Whether elements are allowed to overflow past the max_width limit
allow_overflow: bool,
} }
impl<'a> ChainFormatterShared<'a> { impl<'a> ChainFormatterShared<'a> {
@ -505,6 +561,8 @@ impl<'a> ChainFormatterShared<'a> {
rewrites: Vec::with_capacity(chain.children.len() + 1), rewrites: Vec::with_capacity(chain.children.len() + 1),
fits_single_line: false, fits_single_line: false,
child_count: chain.children.len(), child_count: chain.children.len(),
// TODO(calebcartwright)
allow_overflow: false,
} }
} }
@ -517,6 +575,14 @@ impl<'a> ChainFormatterShared<'a> {
} }
} }
fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
for item in &self.children[..self.children.len() - 1] {
let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?;
self.rewrites.push(rewrite);
}
Some(())
}
// Rewrite the last child. The last child of a chain requires special treatment. We need to // Rewrite the last child. The last child of a chain requires special treatment. We need to
// know whether 'overflowing' the last child make a better formatting: // know whether 'overflowing' the last child make a better formatting:
// //
@ -729,22 +795,12 @@ impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
} }
fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> { fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
Some( let block_end = self.root_ends_with_block;
if self.root_ends_with_block { Some(get_block_child_shape(block_end, context, shape))
shape.block_indent(0)
} else {
shape.block_indent(context.config.tab_spaces())
}
.with_max_width(context.config),
)
} }
fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
for item in &self.shared.children[..self.shared.children.len() - 1] { self.shared.format_children(context, child_shape)
let rewrite = item.rewrite(context, child_shape)?;
self.shared.rewrites.push(rewrite);
}
Some(())
} }
fn format_last_child( fn format_last_child(
@ -808,16 +864,15 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
.visual_indent(self.offset) .visual_indent(self.offset)
.sub_width(self.offset)?; .sub_width(self.offset)?;
let rewrite = item.rewrite(context, child_shape)?; let rewrite = item.rewrite(context, child_shape)?;
match wrap_str(rewrite, context.config.max_width(), shape) { if filtered_str_fits(&rewrite, context.config.max_width(), shape) {
Some(rewrite) => root_rewrite.push_str(&rewrite), root_rewrite.push_str(&rewrite);
None => { } else {
// We couldn't fit in at the visual indent, try the last // We couldn't fit in at the visual indent, try the last
// indent. // indent.
let rewrite = item.rewrite(context, parent_shape)?; let rewrite = item.rewrite(context, parent_shape)?;
root_rewrite.push_str(&rewrite); root_rewrite.push_str(&rewrite);
self.offset = 0; self.offset = 0;
} }
}
self.shared.children = &self.shared.children[1..]; self.shared.children = &self.shared.children[1..];
} }
@ -827,18 +882,17 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
} }
fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> { fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
shape get_visual_style_child_shape(
.with_max_width(context.config) context,
.offset_left(self.offset) shape,
.map(|s| s.visual_indent(0)) self.offset,
// TODO(calebcartwright): self.shared.permissibly_overflowing_parent,
false,
)
} }
fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
for item in &self.shared.children[..self.shared.children.len() - 1] { self.shared.format_children(context, child_shape)
let rewrite = item.rewrite(context, child_shape)?;
self.shared.rewrites.push(rewrite);
}
Some(())
} }
fn format_last_child( fn format_last_child(

View File

@ -1,4 +1,5 @@
use crate::config::file_lines::FileLines; use crate::config::file_lines::FileLines;
use crate::config::macro_names::MacroSelectors;
use crate::config::options::{IgnoreList, WidthHeuristics}; use crate::config::options::{IgnoreList, WidthHeuristics};
/// Trait for types that can be used in `Config`. /// Trait for types that can be used in `Config`.
@ -6,6 +7,14 @@ pub(crate) trait ConfigType: Sized {
/// Returns hint text for use in `Config::print_docs()`. For enum types, this is a /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
/// pipe-separated list of variants; for other types it returns `<type>`. /// pipe-separated list of variants; for other types it returns `<type>`.
fn doc_hint() -> String; fn doc_hint() -> String;
/// Return `true` if the variant (i.e. value of this type) is stable.
///
/// By default, return true for all values. Enums annotated with `#[config_type]`
/// are automatically implemented, based on the `#[unstable_variant]` annotation.
fn stable_variant(&self) -> bool {
true
}
} }
impl ConfigType for bool { impl ConfigType for bool {
@ -38,6 +47,12 @@ impl ConfigType for FileLines {
} }
} }
impl ConfigType for MacroSelectors {
fn doc_hint() -> String {
String::from("[<string>, ...]")
}
}
impl ConfigType for WidthHeuristics { impl ConfigType for WidthHeuristics {
fn doc_hint() -> String { fn doc_hint() -> String {
String::new() String::new()
@ -51,6 +66,13 @@ impl ConfigType for IgnoreList {
} }
macro_rules! create_config { macro_rules! create_config {
// Options passed in to the macro.
//
// - $i: the ident name of the option
// - $ty: the type of the option value
// - $def: the default value of the option
// - $stb: true if the option is stable
// - $dstring: description of the option
($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => ( ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
#[cfg(test)] #[cfg(test)]
use std::collections::HashSet; use std::collections::HashSet;
@ -61,9 +83,12 @@ macro_rules! create_config {
#[derive(Clone)] #[derive(Clone)]
#[allow(unreachable_pub)] #[allow(unreachable_pub)]
pub struct Config { pub struct Config {
// For each config item, we store a bool indicating whether it has // For each config item, we store:
// been accessed and the value, and a bool whether the option was //
// manually initialised, or taken from the default, // - 0: true if the value has been access
// - 1: true if the option was manually initialized
// - 2: the option value
// - 3: true if the option is unstable
$($i: (Cell<bool>, bool, $ty, bool)),+ $($i: (Cell<bool>, bool, $ty, bool)),+
} }
@ -102,6 +127,7 @@ macro_rules! create_config {
| "array_width" | "array_width"
| "chain_width" => self.0.set_heuristics(), | "chain_width" => self.0.set_heuristics(),
"merge_imports" => self.0.set_merge_imports(), "merge_imports" => self.0.set_merge_imports(),
"fn_args_layout" => self.0.set_fn_args_layout(),
&_ => (), &_ => (),
} }
} }
@ -143,24 +169,20 @@ macro_rules! create_config {
fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config { fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
$( $(
if let Some(val) = parsed.$i { if let Some(option_value) = parsed.$i {
if self.$i.3 { let option_stable = self.$i.3;
if $crate::config::config_type::is_stable_option_and_value(
stringify!($i), option_stable, &option_value
) {
self.$i.1 = true; self.$i.1 = true;
self.$i.2 = val; self.$i.2 = option_value;
} else {
if crate::is_nightly_channel!() {
self.$i.1 = true;
self.$i.2 = val;
} else {
eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \
available in nightly channel.", stringify!($i), val);
}
} }
} }
)+ )+
self.set_heuristics(); self.set_heuristics();
self.set_ignore(dir); self.set_ignore(dir);
self.set_merge_imports(); self.set_merge_imports();
self.set_fn_args_layout();
self self
} }
@ -221,12 +243,22 @@ macro_rules! create_config {
match key { match key {
$( $(
stringify!($i) => { stringify!($i) => {
self.$i.1 = true; let option_value = val.parse::<$ty>()
self.$i.2 = val.parse::<$ty>()
.expect(&format!("Failed to parse override for {} (\"{}\") as a {}", .expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
stringify!($i), stringify!($i),
val, val,
stringify!($ty))); stringify!($ty)));
// Users are currently allowed to set unstable
// options/variants via the `--config` options override.
//
// There is ongoing discussion about how to move forward here:
// https://github.com/rust-lang/rustfmt/pull/5379
//
// For now, do not validate whether the option or value is stable,
// just always set it.
self.$i.1 = true;
self.$i.2 = option_value;
} }
)+ )+
_ => panic!("Unknown config key in override: {}", key) _ => panic!("Unknown config key in override: {}", key)
@ -243,14 +275,21 @@ macro_rules! create_config {
| "array_width" | "array_width"
| "chain_width" => self.set_heuristics(), | "chain_width" => self.set_heuristics(),
"merge_imports" => self.set_merge_imports(), "merge_imports" => self.set_merge_imports(),
"fn_args_layout" => self.set_fn_args_layout(),
&_ => (), &_ => (),
} }
} }
#[allow(unreachable_pub)] #[allow(unreachable_pub)]
pub fn is_hidden_option(name: &str) -> bool { pub fn is_hidden_option(name: &str) -> bool {
const HIDE_OPTIONS: [&str; 5] = const HIDE_OPTIONS: [&str; 6] = [
["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"]; "verbose",
"verbose_diff",
"file_lines",
"width_heuristics",
"merge_imports",
"fn_args_layout"
];
HIDE_OPTIONS.contains(&name) HIDE_OPTIONS.contains(&name)
} }
@ -400,6 +439,18 @@ macro_rules! create_config {
} }
} }
fn set_fn_args_layout(&mut self) {
if self.was_set().fn_args_layout() {
eprintln!(
"Warning: the `fn_args_layout` option is deprecated. \
Use `fn_params_layout`. instead"
);
if !self.was_set().fn_params_layout() {
self.fn_params_layout.2 = self.fn_args_layout();
}
}
}
#[allow(unreachable_pub)] #[allow(unreachable_pub)]
/// Returns `true` if the config key was explicitly set and is the default value. /// Returns `true` if the config key was explicitly set and is the default value.
pub fn is_default(&self, key: &str) -> bool { pub fn is_default(&self, key: &str) -> bool {
@ -424,3 +475,38 @@ macro_rules! create_config {
} }
) )
} }
pub(crate) fn is_stable_option_and_value<T>(
option_name: &str,
option_stable: bool,
option_value: &T,
) -> bool
where
T: PartialEq + std::fmt::Debug + ConfigType,
{
let nightly = crate::is_nightly_channel!();
let variant_stable = option_value.stable_variant();
match (nightly, option_stable, variant_stable) {
// Stable with an unstable option
(false, false, _) => {
eprintln!(
"Warning: can't set `{} = {:?}`, unstable features are only \
available in nightly channel.",
option_name, option_value
);
false
}
// Stable with a stable option, but an unstable variant
(false, true, false) => {
eprintln!(
"Warning: can't set `{} = {:?}`, unstable variants are only \
available in nightly channel.",
option_name, option_value
);
false
}
// Nightly: everything allowed
// Stable with stable option and variant: allowed
(true, _, _) | (false, true, true) => true,
}
}

118
src/config/macro_names.rs Normal file
View File

@ -0,0 +1,118 @@
//! This module contains types and functions to support formatting specific macros.
use itertools::Itertools;
use std::{fmt, str};
use serde::{Deserialize, Serialize};
use serde_json as json;
use thiserror::Error;
/// Defines the name of a macro.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub struct MacroName(String);
impl MacroName {
pub fn new(other: String) -> Self {
Self(other)
}
}
impl fmt::Display for MacroName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<MacroName> for String {
fn from(other: MacroName) -> Self {
other.0
}
}
/// Defines a selector to match against a macro.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
pub enum MacroSelector {
Name(MacroName),
All,
}
impl fmt::Display for MacroSelector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Name(name) => name.fmt(f),
Self::All => write!(f, "*"),
}
}
}
impl str::FromStr for MacroSelector {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"*" => MacroSelector::All,
name => MacroSelector::Name(MacroName(name.to_owned())),
})
}
}
/// A set of macro selectors.
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct MacroSelectors(pub Vec<MacroSelector>);
impl fmt::Display for MacroSelectors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.iter().format(", "))
}
}
#[derive(Error, Debug)]
pub enum MacroSelectorsError {
#[error("{0}")]
Json(json::Error),
}
// This impl is needed for `Config::override_value` to work for use in tests.
impl str::FromStr for MacroSelectors {
type Err = MacroSelectorsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let raw: Vec<&str> = json::from_str(s).map_err(MacroSelectorsError::Json)?;
Ok(Self(
raw.into_iter()
.map(|raw| {
MacroSelector::from_str(raw).expect("MacroSelector from_str is infallible")
})
.collect(),
))
}
}
#[cfg(test)]
mod test {
use super::*;
use std::str::FromStr;
#[test]
fn macro_names_from_str() {
let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
assert_eq!(
macro_names,
MacroSelectors(
[
MacroSelector::Name(MacroName("foo".to_owned())),
MacroSelector::All,
MacroSelector::Name(MacroName("bar".to_owned()))
]
.into_iter()
.collect()
)
);
}
#[test]
fn macro_names_display() {
let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
assert_eq!(format!("{}", macro_names), "foo, *, bar");
}
}

View File

@ -13,15 +13,20 @@ pub use crate::config::file_lines::{FileLines, FileName, Range};
#[allow(unreachable_pub)] #[allow(unreachable_pub)]
pub use crate::config::lists::*; pub use crate::config::lists::*;
#[allow(unreachable_pub)] #[allow(unreachable_pub)]
pub use crate::config::macro_names::{MacroSelector, MacroSelectors};
#[allow(unreachable_pub)]
pub use crate::config::options::*; pub use crate::config::options::*;
#[macro_use] #[macro_use]
pub(crate) mod config_type; pub(crate) mod config_type;
#[macro_use] #[macro_use]
#[allow(unreachable_pub)]
pub(crate) mod options; pub(crate) mod options;
pub(crate) mod file_lines; pub(crate) mod file_lines;
#[allow(unreachable_pub)]
pub(crate) mod lists; pub(crate) mod lists;
pub(crate) mod macro_names;
// This macro defines configuration options used in rustfmt. Each option // This macro defines configuration options used in rustfmt. Each option
// is defined as follows: // is defined as follows:
@ -67,6 +72,8 @@ create_config! {
format_macro_matchers: bool, false, false, format_macro_matchers: bool, false, false,
"Format the metavariable matching patterns in macros"; "Format the metavariable matching patterns in macros";
format_macro_bodies: bool, true, false, "Format the bodies of macros"; format_macro_bodies: bool, true, false, "Format the bodies of macros";
skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false,
"Skip formatting the bodies of macros invoked with the following names.";
hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
"Format hexadecimal integer literals"; "Format hexadecimal integer literals";
@ -119,7 +126,9 @@ create_config! {
force_multiline_blocks: bool, false, false, force_multiline_blocks: bool, false, false,
"Force multiline closure bodies and match arms to be wrapped in a block"; "Force multiline closure bodies and match arms to be wrapped in a block";
fn_args_layout: Density, Density::Tall, true, fn_args_layout: Density, Density::Tall, true,
"Control the layout of arguments in a function"; "(deprecated: use fn_params_layout instead)";
fn_params_layout: Density, Density::Tall, true,
"Control the layout of parameters in function signatures.";
brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items"; brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false, control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
"Brace style for control flow constructs"; "Brace style for control flow constructs";
@ -175,7 +184,7 @@ create_config! {
make_backup: bool, false, false, "Backup changed files"; make_backup: bool, false, false, "Backup changed files";
print_misformatted_file_names: bool, false, true, print_misformatted_file_names: bool, false, true,
"Prints the names of mismatched files that were formatted. Prints the names of \ "Prints the names of mismatched files that were formatted. Prints the names of \
files that would be formated when used with `--check` mode. "; files that would be formatted when used with `--check` mode. ";
} }
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -191,6 +200,7 @@ impl PartialConfig {
cloned.width_heuristics = None; cloned.width_heuristics = None;
cloned.print_misformatted_file_names = None; cloned.print_misformatted_file_names = None;
cloned.merge_imports = None; cloned.merge_imports = None;
cloned.fn_args_layout = None;
::toml::to_string(&cloned).map_err(ToTomlError) ::toml::to_string(&cloned).map_err(ToTomlError)
} }
@ -403,11 +413,21 @@ mod test {
use super::*; use super::*;
use std::str; use std::str;
use crate::config::macro_names::MacroName;
use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test}; use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
#[allow(dead_code)] #[allow(dead_code)]
mod mock { mod mock {
use super::super::*; use super::super::*;
use rustfmt_config_proc_macro::config_type;
#[config_type]
pub(crate) enum PartiallyUnstableOption {
V1,
V2,
#[unstable_variant]
V3,
}
create_config! { create_config! {
// Options that are used by the generated functions // Options that are used by the generated functions
@ -427,6 +447,12 @@ mod test {
"Merge imports"; "Merge imports";
merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)"; merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";
// fn_args_layout renamed to fn_params_layout
fn_args_layout: Density, Density::Tall, true,
"(deprecated: use fn_params_layout instead)";
fn_params_layout: Density, Density::Tall, true,
"Control the layout of parameters in a function signatures.";
// Width Heuristics // Width Heuristics
use_small_heuristics: Heuristics, Heuristics::Default, true, use_small_heuristics: Heuristics, Heuristics::Default, true,
"Whether to use different formatting for items and \ "Whether to use different formatting for items and \
@ -451,6 +477,63 @@ mod test {
// Options that are used by the tests // Options that are used by the tests
stable_option: bool, false, true, "A stable option"; stable_option: bool, false, true, "A stable option";
unstable_option: bool, false, false, "An unstable option"; unstable_option: bool, false, false, "An unstable option";
partially_unstable_option: PartiallyUnstableOption, PartiallyUnstableOption::V1, true,
"A partially unstable option";
}
#[cfg(test)]
mod partially_unstable_option {
use super::{Config, PartialConfig, PartiallyUnstableOption};
use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
use std::path::Path;
/// From the config file, we can fill with a stable variant
#[test]
fn test_from_toml_stable_value() {
let toml = r#"
partially_unstable_option = "V2"
"#;
let partial_config: PartialConfig = toml::from_str(toml).unwrap();
let config = Config::default();
let config = config.fill_from_parsed_config(partial_config, Path::new(""));
assert_eq!(
config.partially_unstable_option(),
PartiallyUnstableOption::V2
);
}
/// From the config file, we cannot fill with an unstable variant (stable only)
#[stable_only_test]
#[test]
fn test_from_toml_unstable_value_on_stable() {
let toml = r#"
partially_unstable_option = "V3"
"#;
let partial_config: PartialConfig = toml::from_str(toml).unwrap();
let config = Config::default();
let config = config.fill_from_parsed_config(partial_config, Path::new(""));
assert_eq!(
config.partially_unstable_option(),
// default value from config, i.e. fill failed
PartiallyUnstableOption::V1
);
}
/// From the config file, we can fill with an unstable variant (nightly only)
#[nightly_only_test]
#[test]
fn test_from_toml_unstable_value_on_nightly() {
let toml = r#"
partially_unstable_option = "V3"
"#;
let partial_config: PartialConfig = toml::from_str(toml).unwrap();
let config = Config::default();
let config = config.fill_from_parsed_config(partial_config, Path::new(""));
assert_eq!(
config.partially_unstable_option(),
PartiallyUnstableOption::V3
);
}
} }
} }
@ -489,6 +572,11 @@ mod test {
assert_eq!(config.was_set().verbose(), false); assert_eq!(config.was_set().verbose(), false);
} }
const PRINT_DOCS_STABLE_OPTION: &str = "stable_option <boolean> Default: false";
const PRINT_DOCS_UNSTABLE_OPTION: &str = "unstable_option <boolean> Default: false (unstable)";
const PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION: &str =
"partially_unstable_option [V1|V2|V3 (unstable)] Default: V1";
#[test] #[test]
fn test_print_docs_exclude_unstable() { fn test_print_docs_exclude_unstable() {
use self::mock::Config; use self::mock::Config;
@ -497,10 +585,9 @@ mod test {
Config::print_docs(&mut output, false); Config::print_docs(&mut output, false);
let s = str::from_utf8(&output).unwrap(); let s = str::from_utf8(&output).unwrap();
assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true);
assert_eq!(s.contains("stable_option"), true); assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), false);
assert_eq!(s.contains("unstable_option"), false); assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true);
assert_eq!(s.contains("(unstable)"), false);
} }
#[test] #[test]
@ -511,9 +598,9 @@ mod test {
Config::print_docs(&mut output, true); Config::print_docs(&mut output, true);
let s = str::from_utf8(&output).unwrap(); let s = str::from_utf8(&output).unwrap();
assert_eq!(s.contains("stable_option"), true); assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true);
assert_eq!(s.contains("unstable_option"), true); assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), true);
assert_eq!(s.contains("(unstable)"), true); assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true);
} }
#[test] #[test]
@ -541,6 +628,7 @@ normalize_doc_attributes = false
format_strings = false format_strings = false
format_macro_matchers = false format_macro_matchers = false
format_macro_bodies = true format_macro_bodies = true
skip_macro_invocations = []
hex_literal_case = "Preserve" hex_literal_case = "Preserve"
empty_item_single_line = true empty_item_single_line = true
struct_lit_single_line = true struct_lit_single_line = true
@ -567,7 +655,7 @@ enum_discrim_align_threshold = 0
match_arm_blocks = true match_arm_blocks = true
match_arm_leading_pipes = "Never" match_arm_leading_pipes = "Never"
force_multiline_blocks = false force_multiline_blocks = false
fn_args_layout = "Tall" fn_params_layout = "Tall"
brace_style = "SameLineWhere" brace_style = "SameLineWhere"
control_brace_style = "AlwaysSameLine" control_brace_style = "AlwaysSameLine"
trailing_semicolon = true trailing_semicolon = true
@ -921,4 +1009,45 @@ make_backup = false
assert_eq!(config.single_line_if_else_max_width(), 100); assert_eq!(config.single_line_if_else_max_width(), 100);
} }
} }
#[cfg(test)]
mod partially_unstable_option {
use super::mock::{Config, PartiallyUnstableOption};
use super::*;
/// From the command line, we can override with a stable variant.
#[test]
fn test_override_stable_value() {
let mut config = Config::default();
config.override_value("partially_unstable_option", "V2");
assert_eq!(
config.partially_unstable_option(),
PartiallyUnstableOption::V2
);
}
/// From the command line, we can override with an unstable variant.
#[test]
fn test_override_unstable_value() {
let mut config = Config::default();
config.override_value("partially_unstable_option", "V3");
assert_eq!(
config.partially_unstable_option(),
PartiallyUnstableOption::V3
);
}
}
#[test]
fn test_override_skip_macro_invocations() {
let mut config = Config::default();
config.override_value("skip_macro_invocations", r#"["*", "println"]"#);
assert_eq!(
config.skip_macro_invocations(),
MacroSelectors(vec![
MacroSelector::All,
MacroSelector::Name(MacroName::new("println".to_owned()))
])
);
}
} }

View File

@ -29,9 +29,9 @@ use crate::spanned::Spanned;
use crate::string::{rewrite_string, StringFormat}; use crate::string::{rewrite_string, StringFormat};
use crate::types::{rewrite_path, PathContext}; use crate::types::{rewrite_path, PathContext};
use crate::utils::{ use crate::utils::{
colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes, colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with,
last_line_extendable, last_line_width, mk_sp, outer_attributes, semicolon_for_expr, inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes,
unicode_str_width, wrap_str, semicolon_for_expr, unicode_str_width, wrap_str,
}; };
use crate::vertical::rewrite_with_alignment; use crate::vertical::rewrite_with_alignment;
use crate::visitor::FmtVisitor; use crate::visitor::FmtVisitor;
@ -2050,8 +2050,7 @@ fn choose_rhs<R: Rewrite>(
match (orig_rhs, new_rhs) { match (orig_rhs, new_rhs) {
(Some(ref orig_rhs), Some(ref new_rhs)) (Some(ref orig_rhs), Some(ref new_rhs))
if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape) if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) =>
.is_none() =>
{ {
Some(format!("{}{}", before_space_str, orig_rhs)) Some(format!("{}{}", before_space_str, orig_rhs))
} }

View File

@ -251,8 +251,8 @@ fn flatten_use_trees(
use_trees: Vec<UseTree>, use_trees: Vec<UseTree>,
import_granularity: ImportGranularity, import_granularity: ImportGranularity,
) -> Vec<UseTree> { ) -> Vec<UseTree> {
// Return non-sorted single occurance of the use-trees text string; // Return non-sorted single occurrence of the use-trees text string;
// order is by first occurance of the use-tree. // order is by first occurrence of the use-tree.
use_trees use_trees
.into_iter() .into_iter()
.flat_map(|tree| tree.flatten(import_granularity)) .flat_map(|tree| tree.flatten(import_granularity))

View File

@ -1084,7 +1084,11 @@ pub(crate) fn format_trait(
let item_snippet = context.snippet(item.span); let item_snippet = context.snippet(item.span);
if let Some(lo) = item_snippet.find('/') { if let Some(lo) = item_snippet.find('/') {
// 1 = `{` // 1 = `{`
let comment_hi = body_lo - BytePos(1); let comment_hi = if generics.params.len() > 0 {
generics.span.lo() - BytePos(1)
} else {
body_lo - BytePos(1)
};
let comment_lo = item.span.lo() + BytePos(lo as u32); let comment_lo = item.span.lo() + BytePos(lo as u32);
if comment_lo < comment_hi { if comment_lo < comment_hi {
match recover_missing_comment_in_span( match recover_missing_comment_in_span(
@ -1241,7 +1245,7 @@ fn format_unit_struct(
) -> Option<String> { ) -> Option<String> {
let header_str = format_header(context, p.prefix, p.ident, p.vis, offset); let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
let generics_str = if let Some(generics) = p.generics { let generics_str = if let Some(generics) = p.generics {
let hi = context.snippet_provider.span_before(p.span, ";"); let hi = context.snippet_provider.span_before_last(p.span, ";");
format_generics( format_generics(
context, context,
generics, generics,
@ -2602,7 +2606,7 @@ fn rewrite_params(
&param_items, &param_items,
context context
.config .config
.fn_args_layout() .fn_params_layout()
.to_list_tactic(param_items.len()), .to_list_tactic(param_items.len()),
Separator::Comma, Separator::Comma,
one_line_budget, one_line_budget,

View File

@ -3,7 +3,6 @@
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![allow(clippy::match_like_matches_macro)] #![allow(clippy::match_like_matches_macro)]
#![allow(unreachable_pub)]
#[macro_use] #[macro_use]
extern crate derive_new; extern crate derive_new;

View File

@ -297,9 +297,9 @@ where
} else { } else {
inner_item.as_ref() inner_item.as_ref()
}; };
let mut item_last_line_width = item_last_line.len() + item_sep_len; let mut item_last_line_width = unicode_str_width(item_last_line) + item_sep_len;
if item_last_line.starts_with(&**indent_str) { if item_last_line.starts_with(&**indent_str) {
item_last_line_width -= indent_str.len(); item_last_line_width -= unicode_str_width(indent_str);
} }
if !item.is_substantial() { if !item.is_substantial() {
@ -449,7 +449,7 @@ where
} else if starts_with_newline(comment) { } else if starts_with_newline(comment) {
false false
} else { } else {
comment.trim().contains('\n') || comment.trim().len() > width comment.trim().contains('\n') || unicode_str_width(comment.trim()) > width
}; };
rewrite_comment( rewrite_comment(
@ -465,7 +465,7 @@ where
if !starts_with_newline(comment) { if !starts_with_newline(comment) {
if formatting.align_comments { if formatting.align_comments {
let mut comment_alignment = let mut comment_alignment =
post_comment_alignment(item_max_width, inner_item.len()); post_comment_alignment(item_max_width, unicode_str_width(inner_item));
if first_line_width(&formatted_comment) if first_line_width(&formatted_comment)
+ last_line_width(&result) + last_line_width(&result)
+ comment_alignment + comment_alignment
@ -475,7 +475,7 @@ where
item_max_width = None; item_max_width = None;
formatted_comment = rewrite_post_comment(&mut item_max_width)?; formatted_comment = rewrite_post_comment(&mut item_max_width)?;
comment_alignment = comment_alignment =
post_comment_alignment(item_max_width, inner_item.len()); post_comment_alignment(item_max_width, unicode_str_width(inner_item));
} }
for _ in 0..=comment_alignment { for _ in 0..=comment_alignment {
result.push(' '); result.push(' ');
@ -533,7 +533,7 @@ where
let mut first = true; let mut first = true;
for item in items.clone().into_iter().skip(i) { for item in items.clone().into_iter().skip(i) {
let item = item.as_ref(); let item = item.as_ref();
let inner_item_width = item.inner_as_ref().len(); let inner_item_width = unicode_str_width(item.inner_as_ref());
if !first if !first
&& (item.is_different_group() && (item.is_different_group()
|| item.post_comment.is_none() || item.post_comment.is_none()
@ -552,8 +552,8 @@ where
max_width max_width
} }
fn post_comment_alignment(item_max_width: Option<usize>, inner_item_len: usize) -> usize { fn post_comment_alignment(item_max_width: Option<usize>, inner_item_width: usize) -> usize {
item_max_width.unwrap_or(0).saturating_sub(inner_item_len) item_max_width.unwrap_or(0).saturating_sub(inner_item_width)
} }
pub(crate) struct ListItems<'a, I, F1, F2, F3> pub(crate) struct ListItems<'a, I, F1, F2, F3>

View File

@ -35,8 +35,8 @@ use crate::shape::{Indent, Shape};
use crate::source_map::SpanUtils; use crate::source_map::SpanUtils;
use crate::spanned::Spanned; use crate::spanned::Spanned;
use crate::utils::{ use crate::utils::{
format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces, filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp,
rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt, remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout, NodeIdExt,
}; };
use crate::visitor::FmtVisitor; use crate::visitor::FmtVisitor;
@ -157,7 +157,8 @@ pub(crate) fn rewrite_macro(
) -> Option<String> { ) -> Option<String> {
let should_skip = context let should_skip = context
.skip_context .skip_context
.skip_macro(context.snippet(mac.path.span)); .macros
.skip(context.snippet(mac.path.span));
if should_skip { if should_skip {
None None
} else { } else {
@ -1265,15 +1266,14 @@ impl MacroBranch {
} }
} }
}; };
let new_body = wrap_str(
new_body_snippet.snippet.to_string(), if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) {
config.max_width(), return None;
shape, }
)?;
// Indent the body since it is in a block. // Indent the body since it is in a block.
let indent_str = body_indent.to_string(&config); let indent_str = body_indent.to_string(&config);
let mut new_body = LineClasses::new(new_body.trim_end()) let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end())
.enumerate() .enumerate()
.fold( .fold(
(String::new(), true), (String::new(), true),

View File

@ -2,33 +2,84 @@
use rustc_ast::ast; use rustc_ast::ast;
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use std::collections::HashSet;
/// Take care of skip name stack. You can update it by attributes slice or /// Track which blocks of code are to be skipped when formatting.
/// by other context. Query this context to know if you need skip a block. ///
/// You can update it by:
///
/// - attributes slice
/// - manually feeding values into the underlying contexts
///
/// Query this context to know if you need to skip a block.
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub(crate) struct SkipContext { pub(crate) struct SkipContext {
macros: Vec<String>, pub(crate) macros: SkipNameContext,
attributes: Vec<String>, pub(crate) attributes: SkipNameContext,
} }
impl SkipContext { impl SkipContext {
pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) { pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) {
self.macros.append(&mut get_skip_names("macros", attrs)); self.macros.extend(get_skip_names("macros", attrs));
self.attributes self.attributes.extend(get_skip_names("attributes", attrs));
.append(&mut get_skip_names("attributes", attrs));
} }
pub(crate) fn update(&mut self, mut other: SkipContext) { pub(crate) fn update(&mut self, other: SkipContext) {
self.macros.append(&mut other.macros); let SkipContext { macros, attributes } = other;
self.attributes.append(&mut other.attributes); self.macros.update(macros);
self.attributes.update(attributes);
}
}
/// Track which names to skip.
///
/// Query this context with a string to know whether to skip it.
#[derive(Clone)]
pub(crate) enum SkipNameContext {
All,
Values(HashSet<String>),
}
impl Default for SkipNameContext {
fn default() -> Self {
Self::Values(Default::default())
}
}
impl Extend<String> for SkipNameContext {
fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
match self {
Self::All => {}
Self::Values(values) => values.extend(iter),
}
}
}
impl SkipNameContext {
pub(crate) fn update(&mut self, other: Self) {
match (self, other) {
// If we're already skipping everything, nothing more can be added
(Self::All, _) => {}
// If we want to skip all, set it
(this, Self::All) => {
*this = Self::All;
}
// If we have some new values to skip, add them
(Self::Values(existing_values), Self::Values(new_values)) => {
existing_values.extend(new_values)
}
}
} }
pub(crate) fn skip_macro(&self, name: &str) -> bool { pub(crate) fn skip(&self, name: &str) -> bool {
self.macros.iter().any(|n| n == name) match self {
Self::All => true,
Self::Values(values) => values.contains(name),
}
} }
pub(crate) fn skip_attribute(&self, name: &str) -> bool { pub(crate) fn skip_all(&mut self) {
self.attributes.iter().any(|n| n == name) *self = Self::All;
} }
} }

View File

@ -27,8 +27,13 @@ impl ConfigurationSection {
lazy_static! { lazy_static! {
static ref CONFIG_NAME_REGEX: regex::Regex = static ref CONFIG_NAME_REGEX: regex::Regex =
regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern"); regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern");
// Configuration values, which will be passed to `from_str`:
//
// - must be prefixed with `####`
// - must be wrapped in backticks
// - may by wrapped in double quotes (which will be stripped)
static ref CONFIG_VALUE_REGEX: regex::Regex = static ref CONFIG_VALUE_REGEX: regex::Regex =
regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#) regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#)
.expect("failed creating configuration value pattern"); .expect("failed creating configuration value pattern");
} }

View File

@ -982,11 +982,7 @@ fn rustfmt() -> PathBuf {
assert!( assert!(
me.is_file() || me.with_extension("exe").is_file(), me.is_file() || me.with_extension("exe").is_file(),
"{}", "{}",
if cfg!(release) { "no rustfmt bin, try running `cargo build` or `cargo build --release` before testing"
"no rustfmt bin, try running `cargo build --release` before testing"
} else {
"no rustfmt bin, try running `cargo build` before testing"
}
); );
me me
} }

View File

@ -941,6 +941,28 @@ fn join_bounds_inner(
ast::GenericBound::Trait(..) => last_line_extendable(s), ast::GenericBound::Trait(..) => last_line_extendable(s),
}; };
// Whether a GenericBound item is a PathSegment segment that includes internal array
// that contains more than one item
let is_item_with_multi_items_array = |item: &ast::GenericBound| match item {
ast::GenericBound::Trait(ref poly_trait_ref, ..) => {
let segments = &poly_trait_ref.trait_ref.path.segments;
if segments.len() > 1 {
true
} else {
if let Some(args_in) = &segments[0].args {
matches!(
args_in.deref(),
ast::GenericArgs::AngleBracketed(bracket_args)
if bracket_args.args.len() > 1
)
} else {
false
}
}
}
_ => false,
};
let result = items.iter().enumerate().try_fold( let result = items.iter().enumerate().try_fold(
(String::new(), None, false), (String::new(), None, false),
|(strs, prev_trailing_span, prev_extendable), (i, item)| { |(strs, prev_trailing_span, prev_extendable), (i, item)| {
@ -1035,10 +1057,23 @@ fn join_bounds_inner(
}, },
)?; )?;
if !force_newline // Whether retry the function with forced newline is needed:
&& items.len() > 1 // Only if result is not already multiline and did not exceed line width,
&& (result.0.contains('\n') || result.0.len() > shape.width) // and either there is more than one item;
{ // or the single item is of type `Trait`,
// and any of the internal arrays contains more than one item;
let retry_with_force_newline =
if force_newline || (!result.0.contains('\n') && result.0.len() <= shape.width) {
false
} else {
if items.len() > 1 {
true
} else {
is_item_with_multi_items_array(&items[0])
}
};
if retry_with_force_newline {
join_bounds_inner(context, shape, items, need_indent, true) join_bounds_inner(context, shape, items, need_indent, true)
} else { } else {
Some(result.0) Some(result.0)

View File

@ -384,14 +384,15 @@ macro_rules! skip_out_of_file_lines_range_visitor {
// Wraps String in an Option. Returns Some when the string adheres to the // Wraps String in an Option. Returns Some when the string adheres to the
// Rewrite constraints defined for the Rewrite trait and None otherwise. // Rewrite constraints defined for the Rewrite trait and None otherwise.
pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option<String> { pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option<String> {
if is_valid_str(&filter_normal_code(&s), max_width, shape) { if filtered_str_fits(&s, max_width, shape) {
Some(s) Some(s)
} else { } else {
None None
} }
} }
fn is_valid_str(snippet: &str, max_width: usize, shape: Shape) -> bool { pub(crate) fn filtered_str_fits(snippet: &str, max_width: usize, shape: Shape) -> bool {
let snippet = &filter_normal_code(snippet);
if !snippet.is_empty() { if !snippet.is_empty() {
// First line must fits with `shape.width`. // First line must fits with `shape.width`.
if first_line_width(snippet) > shape.width { if first_line_width(snippet) > shape.width {

View File

@ -8,7 +8,7 @@ use rustc_span::{symbol, BytePos, Pos, Span};
use crate::attr::*; use crate::attr::*;
use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}; use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
use crate::config::Version; use crate::config::Version;
use crate::config::{BraceStyle, Config}; use crate::config::{BraceStyle, Config, MacroSelector};
use crate::coverage::transform_missing_snippet; use crate::coverage::transform_missing_snippet;
use crate::items::{ use crate::items::{
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate, format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
@ -770,6 +770,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
snippet_provider: &'a SnippetProvider, snippet_provider: &'a SnippetProvider,
report: FormatReport, report: FormatReport,
) -> FmtVisitor<'a> { ) -> FmtVisitor<'a> {
let mut skip_context = SkipContext::default();
let mut macro_names = Vec::new();
for macro_selector in config.skip_macro_invocations().0 {
match macro_selector {
MacroSelector::Name(name) => macro_names.push(name.to_string()),
MacroSelector::All => skip_context.macros.skip_all(),
}
}
skip_context.macros.extend(macro_names);
FmtVisitor { FmtVisitor {
parent_context: None, parent_context: None,
parse_sess: parse_session, parse_sess: parse_session,
@ -784,7 +793,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
is_macro_def: false, is_macro_def: false,
macro_rewrite_failure: false, macro_rewrite_failure: false,
report, report,
skip_context: Default::default(), skip_context,
} }
} }

View File

@ -4,6 +4,8 @@ use std::env;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use rustfmt_config_proc_macro::rustfmt_only_ci_test;
/// Run the cargo-fmt executable and return its output. /// Run the cargo-fmt executable and return its output.
fn cargo_fmt(args: &[&str]) -> (String, String) { fn cargo_fmt(args: &[&str]) -> (String, String) {
let mut bin_dir = env::current_exe().unwrap(); let mut bin_dir = env::current_exe().unwrap();
@ -47,7 +49,7 @@ macro_rules! assert_that {
}; };
} }
#[ignore] #[rustfmt_only_ci_test]
#[test] #[test]
fn version() { fn version() {
assert_that!(&["--version"], starts_with("rustfmt ")); assert_that!(&["--version"], starts_with("rustfmt "));
@ -56,7 +58,7 @@ fn version() {
assert_that!(&["--", "--version"], starts_with("rustfmt ")); assert_that!(&["--", "--version"], starts_with("rustfmt "));
} }
#[ignore] #[rustfmt_only_ci_test]
#[test] #[test]
fn print_config() { fn print_config() {
assert_that!( assert_that!(
@ -65,7 +67,7 @@ fn print_config() {
); );
} }
#[ignore] #[rustfmt_only_ci_test]
#[test] #[test]
fn rustfmt_help() { fn rustfmt_help() {
assert_that!(&["--", "--help"], contains("Format Rust code")); assert_that!(&["--", "--help"], contains("Format Rust code"));
@ -73,7 +75,7 @@ fn rustfmt_help() {
assert_that!(&["--", "--help=config"], contains("Configuration Options:")); assert_that!(&["--", "--help=config"], contains("Configuration Options:"));
} }
#[ignore] #[rustfmt_only_ci_test]
#[test] #[test]
fn cargo_fmt_out_of_line_test_modules() { fn cargo_fmt_out_of_line_test_modules() {
// See also https://github.com/rust-lang/rustfmt/issues/5119 // See also https://github.com/rust-lang/rustfmt/issues/5119
@ -96,3 +98,22 @@ fn cargo_fmt_out_of_line_test_modules() {
assert!(stdout.contains(&format!("Diff in {}", path.display()))) assert!(stdout.contains(&format!("Diff in {}", path.display())))
} }
} }
#[rustfmt_only_ci_test]
#[test]
fn cargo_fmt_emits_error_on_line_overflow_true() {
// See also https://github.com/rust-lang/rustfmt/issues/3164
let args = [
"--check",
"--manifest-path",
"tests/cargo-fmt/source/issue_3164/Cargo.toml",
"--",
"--config",
"error_on_line_overflow=true",
];
let (_stdout, stderr) = cargo_fmt(&args);
assert!(stderr.contains(
"line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
))
}

View File

@ -0,0 +1,8 @@
[package]
name = "issue_3164"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,13 @@
#[allow(unused_macros)]
macro_rules! foo {
($id:ident) => {
macro_rules! bar {
($id2:tt) => {
#[cfg(any(target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2))]
fn $id() {}
};
}
};
}
fn main() {}

View File

@ -3,7 +3,7 @@ comment_width = 80
tab_spaces = 2 tab_spaces = 2
newline_style = "Unix" newline_style = "Unix"
brace_style = "SameLineWhere" brace_style = "SameLineWhere"
fn_args_layout = "Tall" fn_params_layout = "Tall"
trailing_comma = "Vertical" trailing_comma = "Vertical"
indent_style = "Block" indent_style = "Block"
reorder_imports = false reorder_imports = false

View File

@ -9,7 +9,7 @@ The directory name './lib/c/d/' conflicts with the './lib/c/d.rs' file name.
* mod g; * mod g;
Module resolution will fail if we look for './lib/c/d/e.rs' or './lib/c/d/e/mod.rs', Module resolution will fail if we look for './lib/c/d/e.rs' or './lib/c/d/e/mod.rs',
so we should fall back to looking for './lib/c/e.rs', which correctly finds the modlue, that so we should fall back to looking for './lib/c/e.rs', which correctly finds the module, that
rustfmt should format. rustfmt should format.
'./lib/c/d/f.rs' and './lib/c/d/g/mod.rs' exist at the default submodule paths so we should be able './lib/c/d/f.rs' and './lib/c/d/g/mod.rs' exist at the default submodule paths so we should be able

View File

@ -9,7 +9,7 @@ The directory name './lib' conflicts with the './lib.rs' file name.
* mod c; * mod c;
Module resolution will fail if we look for './lib/a.rs' or './lib/a/mod.rs', Module resolution will fail if we look for './lib/a.rs' or './lib/a/mod.rs',
so we should fall back to looking for './a.rs', which correctly finds the modlue that so we should fall back to looking for './a.rs', which correctly finds the module that
rustfmt should format. rustfmt should format.
'./lib/b.rs' and './lib/c/mod.rs' exist at the default submodule paths so we should be able './lib/b.rs' and './lib/c/mod.rs' exist at the default submodule paths so we should be able

View File

@ -5,6 +5,8 @@ use std::fs::remove_file;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use rustfmt_config_proc_macro::rustfmt_only_ci_test;
/// Run the rustfmt executable and return its output. /// Run the rustfmt executable and return its output.
fn rustfmt(args: &[&str]) -> (String, String) { fn rustfmt(args: &[&str]) -> (String, String) {
let mut bin_dir = env::current_exe().unwrap(); let mut bin_dir = env::current_exe().unwrap();
@ -47,7 +49,7 @@ macro_rules! assert_that {
}; };
} }
#[ignore] #[rustfmt_only_ci_test]
#[test] #[test]
fn print_config() { fn print_config() {
assert_that!( assert_that!(
@ -76,7 +78,7 @@ fn print_config() {
remove_file("minimal-config").unwrap(); remove_file("minimal-config").unwrap();
} }
#[ignore] #[rustfmt_only_ci_test]
#[test] #[test]
fn inline_config() { fn inline_config() {
// single invocation // single invocation
@ -157,3 +159,18 @@ fn mod_resolution_error_path_attribute_does_not_exist() {
// The path attribute points to a file that does not exist // The path attribute points to a file that does not exist
assert!(stderr.contains("does_not_exist.rs does not exist")); assert!(stderr.contains("does_not_exist.rs does not exist"));
} }
#[test]
fn rustfmt_emits_error_on_line_overflow_true() {
// See also https://github.com/rust-lang/rustfmt/issues/3164
let args = [
"--config",
"error_on_line_overflow=true",
"tests/cargo-fmt/source/issue_3164/src/main.rs",
];
let (_stdout, stderr) = rustfmt(&args);
assert!(stderr.contains(
"line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
))
}

View File

@ -329,7 +329,7 @@ pub enum Feature {
tbm, tbm,
/// POPCNT (Population Count) /// POPCNT (Population Count)
popcnt, popcnt,
/// FXSR (Floating-point context fast save and restor) /// FXSR (Floating-point context fast save and restore)
fxsr, fxsr,
/// XSAVE (Save Processor Extended States) /// XSAVE (Save Processor Extended States)
xsave, xsave,

View File

@ -0,0 +1,140 @@
impl Default for WhitespaceCharacters {
fn default() -> Self {
Self {
space: '·', // U+00B7
nbsp: '', // U+237D
tab: '', // U+2192
newline: '', // U+23CE
}
}
}
const RAINBOWS: &[&str] = &[
"rаinЬοѡ", // hue: 0
"raіnЬοw", // hue: 2
"rаіɴЬow", // hue: 2
"raіɴЬoѡ", // hue: 8
"ʀainЬow", // hue: 8
"ʀaіɴboѡ", // hue: 8
"ʀаіnbοw", // hue: 11
"rainЬoѡ", // hue: 14
"raіɴbow", // hue: 14
"rаЬow", // hue: 20
"raіnЬow", // hue: 26
"ʀaiɴbοw", // hue: 32
"raіɴboѡ", // hue: 35
"rаiɴbow", // hue: 35
"rаіnbοw", // hue: 38
"rаinЬow", // hue: 47
"ʀaіnboѡ", // hue: 47
"ʀaіnЬoѡ", // hue: 47
"ʀаіɴbοw", // hue: 53
"ʀaіnЬοѡ", // hue: 57
"raiɴЬoѡ", // hue: 68
"ʀainbοѡ", // hue: 68
"ʀаinboѡ", // hue: 68
"ʀаiɴbοw", // hue: 68
"ʀаіnbow", // hue: 68
"rаіnЬοѡ", // hue: 69
"ʀainЬοw", // hue: 71
"raiɴbow", // hue: 73
"raіnЬoѡ", // hue: 74
"rаіɴbοw", // hue: 77
"raіnЬοѡ", // hue: 81
"raiɴЬow", // hue: 83
"ʀainbοw", // hue: 83
"ʀаinbow", // hue: 83
"ʀаiɴbοѡ", // hue: 83
"ʀаіnboѡ", // hue: 83
"ʀаіɴЬοѡ", // hue: 84
"rainЬow", // hue: 85
"ʀаЬοw", // hue: 86
"ʀаіnbοѡ", // hue: 89
"ʀаіnЬοw", // hue: 92
"rаiɴbοw", // hue: 95
"ʀаіɴbοѡ", // hue: 98
"ʀаЬοѡ", // hue: 99
"raіnbοw", // hue: 101
"ʀаіɴЬοw", // hue: 101
"ʀaiɴboѡ", // hue: 104
"ʀаinbοѡ", // hue: 104
"rаiɴbοѡ", // hue: 107
"ʀаinЬοw", // hue: 107
"rаЬοw", // hue: 110
"rаіnboѡ", // hue: 110
"rаіnbοѡ", // hue: 113
"ʀainЬοѡ", // hue: 114
"rаіnЬοw", // hue: 116
"ʀaіɴЬow", // hue: 116
"rаinbοw", // hue: 122
"ʀаіɴboѡ", // hue: 125
"rаinbοѡ", // hue: 131
"rainbow", // hue: 134
"rаinЬοw", // hue: 134
"ʀаiɴboѡ", // hue: 140
"rainЬοѡ", // hue: 141
"raіɴЬow", // hue: 143
"ʀainЬoѡ", // hue: 143
"ʀaіɴbow", // hue: 143
"ʀainbow", // hue: 148
"rаіɴboѡ", // hue: 149
"ʀainboѡ", // hue: 155
"ʀaіnbow", // hue: 155
"ʀaіnЬow", // hue: 155
"raiɴbοw", // hue: 158
"ʀаЬoѡ", // hue: 158
"rainbοw", // hue: 160
"rаinbow", // hue: 160
"ʀaіɴbοѡ", // hue: 164
"ʀаiɴbow", // hue: 164
"ʀаіnЬoѡ", // hue: 164
"ʀaiɴЬοѡ", // hue: 165
"rаiɴboѡ", // hue: 167
"ʀaіɴЬοw", // hue: 167
"ʀaіɴЬοѡ", // hue: 171
"raіnboѡ", // hue: 173
"ʀаіɴЬoѡ", // hue: 173
"rаіɴbοѡ", // hue: 176
"ʀаinЬow", // hue: 176
"rаЬοѡ", // hue: 177
"rаіɴЬοw", // hue: 179
"ʀаinЬoѡ", // hue: 179
"ʀаіɴbow", // hue: 179
"rаЬoѡ", // hue: 182
"raіɴbοѡ", // hue: 188
"rаіnЬoѡ", // hue: 188
"raiɴЬοѡ", // hue: 189
"raіɴЬοw", // hue: 191
"ʀaіɴbοw", // hue: 191
"ʀаіnЬow", // hue: 191
"rainbοѡ", // hue: 194
"rаinboѡ", // hue: 194
"rаіnbow", // hue: 194
"rainЬοw", // hue: 197
"rаinЬoѡ", // hue: 206
"rаіɴbow", // hue: 206
"rаіɴЬοѡ", // hue: 210
"ʀaiɴЬow", // hue: 212
"raіɴbοw", // hue: 218
"rаіnЬow", // hue: 218
"ʀaiɴbοѡ", // hue: 221
"ʀaiɴЬοw", // hue: 224
"ʀaіnbοѡ", // hue: 227
"raiɴboѡ", // hue: 230
"ʀaіnbοw", // hue: 230
"ʀaіnЬοw", // hue: 230
"ʀаinЬοѡ", // hue: 231
"rainboѡ", // hue: 232
"raіnbow", // hue: 232
"ʀаіɴЬow", // hue: 233
"ʀaіɴЬoѡ", // hue: 239
"ʀаіnЬοѡ", // hue: 246
"raiɴbοѡ", // hue: 248
"ʀаЬow", // hue: 248
"raіɴЬοѡ", // hue: 249
"raiɴЬοw", // hue: 251
"rаіɴЬoѡ", // hue: 251
"ʀaiɴbow", // hue: 251
"ʀаinbοw", // hue: 251
"raіnbοѡ", // hue: 254
];

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Compressed // rustfmt-fn_params_layout: Compressed
// Function arguments density // Function arguments density
trait Lorem { trait Lorem {

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Tall // rustfmt-fn_params_layout: Tall
// Function arguments density // Function arguments density
trait Lorem { trait Lorem {

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Vertical // rustfmt-fn_params_layout: Vertical
// Function arguments density // Function arguments density
trait Lorem { trait Lorem {

View File

@ -36,7 +36,7 @@ enum StructLikeVariants {
Normal(u32, String, ), Normal(u32, String, ),
StructLike { x: i32, // Test comment StructLike { x: i32, // Test comment
// Pre-comment // Pre-comment
#[Attr50] y: SomeType, // Aanother Comment #[Attr50] y: SomeType, // Another Comment
}, SL { a: A } }, SL { a: A }
} }

View File

@ -1,5 +1,5 @@
// rustfmt-normalize_comments: true // rustfmt-normalize_comments: true
// rustfmt-fn_args_layout: Vertical // rustfmt-fn_params_layout: Vertical
// rustfmt-brace_style: AlwaysNextLine // rustfmt-brace_style: AlwaysNextLine
// Case with only one variable. // Case with only one variable.

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Compressed // rustfmt-fn_params_layout: Compressed
// Test some of the ways function signatures can be customised. // Test some of the ways function signatures can be customised.
// Test compressed layout of args. // Test compressed layout of args.

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Vertical // rustfmt-fn_params_layout: Vertical
// Empty list should stay on one line. // Empty list should stay on one line.
fn do_bar( fn do_bar(

View File

@ -0,0 +1,26 @@
// rustfmt-format_macro_bodies: true
// with comments
macro_rules! macros {
() => {{
Struct {
field: (
42 + //comment 1
42
//comment 2
),
};
}};
}
// without comments
macro_rules! macros {
() => {{
Struct {
field: (
42 +
42
),
};
}};
}

View File

@ -0,0 +1,23 @@
// output doesn't get corrupted when using comments within generic type parameters of a trait
pub trait Something<
A,
// some comment
B,
C
> {
fn a(&self, x: A) -> i32;
fn b(&self, x: B) -> i32;
fn c(&self, x: C) -> i32;
}
pub trait SomethingElse<
A,
/* some comment */
B,
C
> {
fn a(&self, x: A) -> i32;
fn b(&self, x: B) -> i32;
fn c(&self, x: C) -> i32;
}

View File

@ -0,0 +1,149 @@
// rustfmt-version: One
// Based on the issue description
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write1 + fmt::Write2
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write + Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write + Printer1<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + Printer2<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
// Some test cases to ensure other cases formatting were not changed
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
>,
> {
}
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
> + fmt::Write1
+ fmt::Write2,
> {
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
)
{
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
) + fmt::Write
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: for<> FnMut(
&mut ProbeContext<>,
ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
),
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: for<> FnMut(
&mut ProbeContext<>,
ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
) + fmt::Write,
{
}
fn build_sorted_static_get_entry_names(
mut entries: entryyyyyyyy,
) -> (
impl Fn(
AlphabeticalTraversal,
Seconddddddddddddddddddddddddddddddddddd
) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+ Sendddddddddddddddddddddddddddddddddddddddddddd
) {
}
pub trait SomeTrait:
Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
{
}
trait B = where
for<'b> &'b Self: Send
+ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;

View File

@ -0,0 +1,149 @@
// rustfmt-version: Two
// Based on the issue description
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write1 + fmt::Write2
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write + Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write + Printer1<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + Printer2<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
// Some test cases to ensure other cases formatting were not changed
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
>,
> {
}
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
> + fmt::Write1
+ fmt::Write2,
> {
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
)
{
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
) + fmt::Write
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: for<> FnMut(
&mut ProbeContext<>,
ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
),
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: for<> FnMut(
&mut ProbeContext<>,
ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
) + fmt::Write,
{
}
fn build_sorted_static_get_entry_names(
mut entries: entryyyyyyyy,
) -> (
impl Fn(
AlphabeticalTraversal,
Seconddddddddddddddddddddddddddddddddddd
) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+ Sendddddddddddddddddddddddddddddddddddddddddddd
) {
}
pub trait SomeTrait:
Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
{
}
trait B = where
for<'b> &'b Self: Send
+ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;

View File

@ -0,0 +1,29 @@
// rustfmt-max_width: 160
// rustfmt-fn_call_width: 96
// rustfmt-fn_args_layout: Compressed
// rustfmt-trailing_comma: Always
// rustfmt-wrap_comments: true
fn foo() {
for elem in try!(gen_epub_book::ops::parse_descriptor_file(&mut try!(File::open(&opts.source_file.1).map_err(|_| {
gen_epub_book::Error::Io {
desc: "input file",
op: "open",
more: None,
}
})),
"input file")) {
println!("{}", elem);
}
}
fn write_content() {
io::copy(try!(File::open(in_f).map_err(|_| {
Error::Io {
desc: "Content",
op: "open",
more: None,
}
})),
w);
}

View File

@ -0,0 +1,4 @@
fn main() {
let x = 1;
;let y = 3;
}

View File

@ -0,0 +1,6 @@
fn main() {;7
}
fn main() {
;7
}

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: ["*"]
// Should skip this invocation
items!(
const _: u8 = 0;
);
// Should skip this invocation
renamed_items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: ["*","items"]
// Should skip this invocation
items!(
const _: u8 = 0;
);
// Should also skip this invocation, as the wildcard covers it
renamed_items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: []
// Should not skip this invocation
items!(
const _: u8 = 0;
);
// Should not skip this invocation
renamed_items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: ["items"]
// Should skip this invocation
items!(
const _: u8 = 0;
);
// Should not skip this invocation
renamed_items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,6 @@
// rustfmt-skip_macro_invocations: ["unknown"]
// Should not skip this invocation
items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,16 @@
// rustfmt-skip_macro_invocations: ["foo","bar"]
// Should skip this invocation
foo!(
const _: u8 = 0;
);
// Should skip this invocation
bar!(
const _: u8 = 0;
);
// Should not skip this invocation
baz!(
const _: u8 = 0;
);

View File

@ -0,0 +1,6 @@
// rustfmt-skip_macro_invocations: ["items"]
// Should not skip this invocation
self::items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,6 @@
// rustfmt-skip_macro_invocations: ["self::items"]
// Should skip this invocation
self::items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,6 @@
// rustfmt-skip_macro_invocations: ["self::items"]
// Should not skip this invocation
items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,32 @@
// rustfmt-skip_macro_invocations: ["aaa","ccc"]
// These tests demonstrate a realistic use case with use aliases.
// The use statements should not impact functionality in any way.
use crate::{aaa, bbb, ddd};
// No use alias, invocation in list
// Should skip this invocation
aaa!(
const _: u8 = 0;
);
// Use alias, invocation in list
// Should skip this invocation
use crate::bbb as ccc;
ccc!(
const _: u8 = 0;
);
// Use alias, invocation not in list
// Should not skip this invocation
use crate::ddd as eee;
eee!(
const _: u8 = 0;
);
// No use alias, invocation not in list
// Should not skip this invocation
fff!(
const _: u8 = 0;
);

View File

@ -1,4 +1,4 @@
// Test tuple litterals // Test tuple literals
fn foo() { fn foo() {
let a = (a, a, a, a, a); let a = (a, a, a, a, a);

View File

@ -11,6 +11,6 @@
/// ///
fn foo() {} fn foo() {}
/// A long commment for wrapping /// A long comment for wrapping
/// This is a long long long long long long long long long long long long long long long long long long long long sentence. /// This is a long long long long long long long long long long long long long long long long long long long long sentence.
fn bar() {} fn bar() {}

View File

@ -314,7 +314,7 @@ pub enum Feature {
tbm, tbm,
/// POPCNT (Population Count) /// POPCNT (Population Count)
popcnt, popcnt,
/// FXSR (Floating-point context fast save and restor) /// FXSR (Floating-point context fast save and restore)
fxsr, fxsr,
/// XSAVE (Save Processor Extended States) /// XSAVE (Save Processor Extended States)
xsave, xsave,

View File

@ -0,0 +1,140 @@
impl Default for WhitespaceCharacters {
fn default() -> Self {
Self {
space: '·', // U+00B7
nbsp: '', // U+237D
tab: '', // U+2192
newline: '', // U+23CE
}
}
}
const RAINBOWS: &[&str] = &[
"rаinЬοѡ", // hue: 0
"raіnЬοw", // hue: 2
"rаіɴЬow", // hue: 2
"raіɴЬoѡ", // hue: 8
"ʀainЬow", // hue: 8
"ʀaіɴboѡ", // hue: 8
"ʀаіnbοw", // hue: 11
"rainЬoѡ", // hue: 14
"raіɴbow", // hue: 14
"rаЬow", // hue: 20
"raіnЬow", // hue: 26
"ʀaiɴbοw", // hue: 32
"raіɴboѡ", // hue: 35
"rаiɴbow", // hue: 35
"rаіnbοw", // hue: 38
"rаinЬow", // hue: 47
"ʀaіnboѡ", // hue: 47
"ʀaіnЬoѡ", // hue: 47
"ʀаіɴbοw", // hue: 53
"ʀaіnЬοѡ", // hue: 57
"raiɴЬoѡ", // hue: 68
"ʀainbοѡ", // hue: 68
"ʀаinboѡ", // hue: 68
"ʀаiɴbοw", // hue: 68
"ʀаіnbow", // hue: 68
"rаіnЬοѡ", // hue: 69
"ʀainЬοw", // hue: 71
"raiɴbow", // hue: 73
"raіnЬoѡ", // hue: 74
"rаіɴbοw", // hue: 77
"raіnЬοѡ", // hue: 81
"raiɴЬow", // hue: 83
"ʀainbοw", // hue: 83
"ʀаinbow", // hue: 83
"ʀаiɴbοѡ", // hue: 83
"ʀаіnboѡ", // hue: 83
"ʀаіɴЬοѡ", // hue: 84
"rainЬow", // hue: 85
"ʀаЬοw", // hue: 86
"ʀаіnbοѡ", // hue: 89
"ʀаіnЬοw", // hue: 92
"rаiɴbοw", // hue: 95
"ʀаіɴbοѡ", // hue: 98
"ʀаЬοѡ", // hue: 99
"raіnbοw", // hue: 101
"ʀаіɴЬοw", // hue: 101
"ʀaiɴboѡ", // hue: 104
"ʀаinbοѡ", // hue: 104
"rаiɴbοѡ", // hue: 107
"ʀаinЬοw", // hue: 107
"rаЬοw", // hue: 110
"rаіnboѡ", // hue: 110
"rаіnbοѡ", // hue: 113
"ʀainЬοѡ", // hue: 114
"rаіnЬοw", // hue: 116
"ʀaіɴЬow", // hue: 116
"rаinbοw", // hue: 122
"ʀаіɴboѡ", // hue: 125
"rаinbοѡ", // hue: 131
"rainbow", // hue: 134
"rаinЬοw", // hue: 134
"ʀаiɴboѡ", // hue: 140
"rainЬοѡ", // hue: 141
"raіɴЬow", // hue: 143
"ʀainЬoѡ", // hue: 143
"ʀaіɴbow", // hue: 143
"ʀainbow", // hue: 148
"rаіɴboѡ", // hue: 149
"ʀainboѡ", // hue: 155
"ʀaіnbow", // hue: 155
"ʀaіnЬow", // hue: 155
"raiɴbοw", // hue: 158
"ʀаЬoѡ", // hue: 158
"rainbοw", // hue: 160
"rаinbow", // hue: 160
"ʀaіɴbοѡ", // hue: 164
"ʀаiɴbow", // hue: 164
"ʀаіnЬoѡ", // hue: 164
"ʀaiɴЬοѡ", // hue: 165
"rаiɴboѡ", // hue: 167
"ʀaіɴЬοw", // hue: 167
"ʀaіɴЬοѡ", // hue: 171
"raіnboѡ", // hue: 173
"ʀаіɴЬoѡ", // hue: 173
"rаіɴbοѡ", // hue: 176
"ʀаinЬow", // hue: 176
"rаЬοѡ", // hue: 177
"rаіɴЬοw", // hue: 179
"ʀаinЬoѡ", // hue: 179
"ʀаіɴbow", // hue: 179
"rаЬoѡ", // hue: 182
"raіɴbοѡ", // hue: 188
"rаіnЬoѡ", // hue: 188
"raiɴЬοѡ", // hue: 189
"raіɴЬοw", // hue: 191
"ʀaіɴbοw", // hue: 191
"ʀаіnЬow", // hue: 191
"rainbοѡ", // hue: 194
"rаinboѡ", // hue: 194
"rаіnbow", // hue: 194
"rainЬοw", // hue: 197
"rаinЬoѡ", // hue: 206
"rаіɴbow", // hue: 206
"rаіɴЬοѡ", // hue: 210
"ʀaiɴЬow", // hue: 212
"raіɴbοw", // hue: 218
"rаіnЬow", // hue: 218
"ʀaiɴbοѡ", // hue: 221
"ʀaiɴЬοw", // hue: 224
"ʀaіnbοѡ", // hue: 227
"raiɴboѡ", // hue: 230
"ʀaіnbοw", // hue: 230
"ʀaіnЬοw", // hue: 230
"ʀаinЬοѡ", // hue: 231
"rainboѡ", // hue: 232
"raіnbow", // hue: 232
"ʀаіɴЬow", // hue: 233
"ʀaіɴЬoѡ", // hue: 239
"ʀаіnЬοѡ", // hue: 246
"raiɴbοѡ", // hue: 248
"ʀаЬow", // hue: 248
"raіɴЬοѡ", // hue: 249
"raiɴЬοw", // hue: 251
"rаіɴЬoѡ", // hue: 251
"ʀaiɴbow", // hue: 251
"ʀаinbοw", // hue: 251
"raіnbοѡ", // hue: 254
];

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Compressed // rustfmt-fn_params_layout: Compressed
// Function arguments density // Function arguments density
trait Lorem { trait Lorem {

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Tall // rustfmt-fn_params_layout: Tall
// Function arguments density // Function arguments density
trait Lorem { trait Lorem {

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Vertical // rustfmt-fn_params_layout: Vertical
// Function arguments density // Function arguments density
trait Lorem { trait Lorem {

View File

@ -43,7 +43,7 @@ enum StructLikeVariants {
x: i32, // Test comment x: i32, // Test comment
// Pre-comment // Pre-comment
#[Attr50] #[Attr50]
y: SomeType, // Aanother Comment y: SomeType, // Another Comment
}, },
SL { SL {
a: A, a: A,

View File

@ -1,5 +1,5 @@
// rustfmt-normalize_comments: true // rustfmt-normalize_comments: true
// rustfmt-fn_args_layout: Vertical // rustfmt-fn_params_layout: Vertical
// rustfmt-brace_style: AlwaysNextLine // rustfmt-brace_style: AlwaysNextLine
// Case with only one variable. // Case with only one variable.

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Compressed // rustfmt-fn_params_layout: Compressed
// Test some of the ways function signatures can be customised. // Test some of the ways function signatures can be customised.
// Test compressed layout of args. // Test compressed layout of args.

View File

@ -1,4 +1,4 @@
// rustfmt-fn_args_layout: Vertical // rustfmt-fn_params_layout: Vertical
// Empty list should stay on one line. // Empty list should stay on one line.
fn do_bar() -> u8 { fn do_bar() -> u8 {

View File

@ -0,0 +1,6 @@
// rustfmt-format_macro_matchers: false
macro_rules! foo {
($a:ident : $b:ty) => {};
($a:ident $b:ident $c:ident) => {};
}

View File

@ -0,0 +1,6 @@
// rustfmt-format_macro_matchers: true
macro_rules! foo {
($a:ident : $b:ty) => {};
($a:ident $b:ident $c:ident) => {};
}

View File

@ -0,0 +1,26 @@
// rustfmt-format_macro_bodies: false
// with comments
macro_rules! macros {
() => {{
Struct {
field: (
42 + //comment 1
42
//comment 2
),
};
}};
}
// without comments
macro_rules! macros {
() => {{
Struct {
field: (
42 +
42
),
};
}};
}

View File

@ -0,0 +1,21 @@
// rustfmt-format_macro_bodies: true
// with comments
macro_rules! macros {
() => {{
Struct {
field: (
42 + //comment 1
42
//comment 2
),
};
}};
}
// without comments
macro_rules! macros {
() => {{
Struct { field: (42 + 42) };
}};
}

View File

@ -0,0 +1,19 @@
// output doesn't get corrupted when using comments within generic type parameters of a trait
pub trait Something<
A,
// some comment
B,
C,
>
{
fn a(&self, x: A) -> i32;
fn b(&self, x: B) -> i32;
fn c(&self, x: C) -> i32;
}
pub trait SomethingElse<A, /* some comment */ B, C> {
fn a(&self, x: A) -> i32;
fn b(&self, x: B) -> i32;
fn c(&self, x: C) -> i32;
}

View File

@ -0,0 +1,150 @@
// rustfmt-version: One
// Based on the issue description
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write1
+ fmt::Write2
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write
+ Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write
+ Printer1<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + Printer2<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
// Some test cases to ensure other cases formatting were not changed
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
>,
> {
}
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
> + fmt::Write1
+ fmt::Write2,
> {
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
),
{
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
) + fmt::Write,
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: FnMut(
&mut ProbeContext,
ty::PolyTraitRefffffffffffffffffffffffffffffffff,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
),
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: FnMut(
&mut ProbeContext,
ty::PolyTraitRefffffffffffffffffffffffffffffffff,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
) + fmt::Write,
{
}
fn build_sorted_static_get_entry_names(
mut entries: entryyyyyyyy,
) -> (impl Fn(
AlphabeticalTraversal,
Seconddddddddddddddddddddddddddddddddddd,
) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+ Sendddddddddddddddddddddddddddddddddddddddddddd) {
}
pub trait SomeTrait:
Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
{
}
trait B = where
for<'b> &'b Self: Send
+ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;

View File

@ -0,0 +1,152 @@
// rustfmt-version: Two
// Based on the issue description
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write
{
//
}
pub trait PrettyPrinter<'tcx>:
Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + fmt::Write1
+ fmt::Write2
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write
+ Printer<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
pub trait PrettyPrinter<'tcx>:
fmt::Write
+ Printer1<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
> + Printer2<
'tcx,
Error = fmt::Error,
Path = Self,
Region = Self,
Type = Self,
DynExistential = Self,
Const = Self,
>
{
//
}
// Some test cases to ensure other cases formatting were not changed
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
>,
> {
}
fn f() -> Box<
FnMut() -> Thing<
WithType = LongItemName,
Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
> + fmt::Write1
+ fmt::Write2,
> {
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
),
{
}
fn foo<F>(foo2: F)
where
F: Fn(
// this comment is deleted
) + fmt::Write,
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: FnMut(
&mut ProbeContext,
ty::PolyTraitRefffffffffffffffffffffffffffffffff,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
),
{
}
fn elaborate_bounds<F>(mut mk_cand: F)
where
F: FnMut(
&mut ProbeContext,
ty::PolyTraitRefffffffffffffffffffffffffffffffff,
tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
) + fmt::Write,
{
}
fn build_sorted_static_get_entry_names(
mut entries: entryyyyyyyy,
) -> (
impl Fn(
AlphabeticalTraversal,
Seconddddddddddddddddddddddddddddddddddd,
) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+ Sendddddddddddddddddddddddddddddddddddddddddddd
) {
}
pub trait SomeTrait:
Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
{
}
trait B = where
for<'b> &'b Self: Send
+ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;

View File

@ -1,7 +1,7 @@
// rustfmt-brace_style: SameLineWhere // rustfmt-brace_style: SameLineWhere
// rustfmt-comment_width: 100 // rustfmt-comment_width: 100
// rustfmt-edition: 2018 // rustfmt-edition: 2018
// rustfmt-fn_args_layout: Compressed // rustfmt-fn_params_layout: Compressed
// rustfmt-hard_tabs: false // rustfmt-hard_tabs: false
// rustfmt-match_block_trailing_comma: true // rustfmt-match_block_trailing_comma: true
// rustfmt-max_width: 100 // rustfmt-max_width: 100

View File

@ -0,0 +1,4 @@
// Test /* comment */ inside trait generics does not get duplicated.
trait Test</* comment */ T> {}
trait TestTwo</* comment */ T, /* comment */ V> {}

View File

@ -0,0 +1,33 @@
// rustfmt-max_width: 160
// rustfmt-fn_call_width: 96
// rustfmt-fn_args_layout: Compressed
// rustfmt-trailing_comma: Always
// rustfmt-wrap_comments: true
fn foo() {
for elem in try!(gen_epub_book::ops::parse_descriptor_file(
&mut try!(File::open(&opts.source_file.1).map_err(|_| {
gen_epub_book::Error::Io {
desc: "input file",
op: "open",
more: None,
}
})),
"input file"
)) {
println!("{}", elem);
}
}
fn write_content() {
io::copy(
try!(File::open(in_f).map_err(|_| {
Error::Io {
desc: "Content",
op: "open",
more: None,
}
})),
w,
);
}

View File

@ -0,0 +1,2 @@
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding::
BluetoothRemoteGATTServerMethods;

View File

@ -0,0 +1,4 @@
fn main() {
let x = 1;
let y = 3;
}

View File

@ -0,0 +1,7 @@
fn main() {
7
}
fn main() {
7
}

View File

@ -0,0 +1,13 @@
//rustfmt-format_macro_bodies: true
macro_rules! mto_text_left {
($buf:ident, $n:ident, $pos:ident, $state:ident) => {{
let cursor = loop {
state = match iter.next() {
None if $pos == DP::Start => break last_char_idx($buf),
None /*some comment */ => break 0,
};
};
Ok(saturate_cursor($buf, cursor))
}};
}

View File

@ -0,0 +1,8 @@
type Foo = impl Send;
struct Struct<
const C: usize = {
let _: Foo = ();
//~^ ERROR: mismatched types
0
},
>;

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: ["*"]
// Should skip this invocation
items!(
const _: u8 = 0;
);
// Should skip this invocation
renamed_items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: ["*","items"]
// Should skip this invocation
items!(
const _: u8 = 0;
);
// Should also skip this invocation, as the wildcard covers it
renamed_items!(
const _: u8 = 0;
);

View File

@ -0,0 +1,11 @@
// rustfmt-skip_macro_invocations: []
// Should not skip this invocation
items!(
const _: u8 = 0;
);
// Should not skip this invocation
renamed_items!(
const _: u8 = 0;
);

Some files were not shown because too many files have changed in this diff Show More