Skip to content

Commit 15433e8

Browse files
committed
Auto merge of #5843 - alexcrichton:idioms-for, r=alexcrichton
Add a `--edition-idioms` flag to `cargo fix` This, like `--prepare-for`, will be part of the transition guide which automatically applies the necessary lint group from the compiler to associated code. cc rust-lang/rust#52679
2 parents e3a90f2 + 80f9d31 commit 15433e8

File tree

4 files changed

+117
-1
lines changed

4 files changed

+117
-1
lines changed

src/bin/cargo/commands/fix.rs

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ pub fn cli() -> App {
5151
.conflicts_with("edition")
5252
.hidden(true),
5353
)
54+
.arg(
55+
Arg::with_name("idioms")
56+
.long("edition-idioms")
57+
.help("Fix warnings to migrate to the idioms of an edition")
58+
)
5459
.arg(
5560
Arg::with_name("allow-no-vcs")
5661
.long("allow-no-vcs")
@@ -126,6 +131,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
126131
ops::fix(&ws, &mut ops::FixOptions {
127132
edition: args.is_present("edition"),
128133
prepare_for: args.value_of("prepare-for"),
134+
idioms: args.is_present("idioms"),
129135
compile_opts: opts,
130136
allow_dirty: args.is_present("allow-dirty"),
131137
allow_no_vcs: args.is_present("allow-no-vcs"),

src/cargo/ops/fix.rs

+23
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ const BROKEN_CODE_ENV: &str = "__CARGO_FIX_BROKEN_CODE";
2424
const PREPARE_FOR_ENV: &str = "__CARGO_FIX_PREPARE_FOR";
2525
const EDITION_ENV: &str = "__CARGO_FIX_EDITION";
2626

27+
const IDIOMS_ENV: &str = "__CARGO_FIX_IDIOMS";
28+
2729
pub struct FixOptions<'a> {
2830
pub edition: bool,
2931
pub prepare_for: Option<&'a str>,
32+
pub idioms: bool,
3033
pub compile_opts: CompileOptions<'a>,
3134
pub allow_dirty: bool,
3235
pub allow_no_vcs: bool,
@@ -59,6 +62,12 @@ pub fn fix(ws: &Workspace, opts: &mut FixOptions) -> CargoResult<()> {
5962
edition.to_string(),
6063
));
6164
}
65+
if opts.idioms {
66+
opts.compile_opts.build_config.extra_rustc_env.push((
67+
IDIOMS_ENV.to_string(),
68+
"1".to_string(),
69+
));
70+
}
6271
opts.compile_opts.build_config.cargo_as_rustc_wrapper = true;
6372
*opts.compile_opts.build_config.rustfix_diagnostic_server.borrow_mut() =
6473
Some(RustfixDiagnosticServer::new()?);
@@ -471,6 +480,7 @@ fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> {
471480
struct FixArgs {
472481
file: Option<PathBuf>,
473482
prepare_for_edition: PrepareFor,
483+
idioms: bool,
474484
enabled_edition: Option<String>,
475485
other: Vec<OsString>,
476486
}
@@ -512,6 +522,7 @@ impl FixArgs {
512522
} else if env::var(EDITION_ENV).is_ok() {
513523
ret.prepare_for_edition = PrepareFor::Next;
514524
}
525+
ret.idioms = env::var(IDIOMS_ENV).is_ok();
515526
return ret
516527
}
517528

@@ -523,6 +534,12 @@ impl FixArgs {
523534
.arg("--cap-lints=warn");
524535
if let Some(edition) = &self.enabled_edition {
525536
cmd.arg("--edition").arg(edition);
537+
if self.idioms {
538+
match &edition[..] {
539+
"2018" => { cmd.arg("-Wrust-2018-idioms"); }
540+
_ => {}
541+
}
542+
}
526543
}
527544
match &self.prepare_for_edition {
528545
PrepareFor::Edition(edition) => {
@@ -569,6 +586,12 @@ impl FixArgs {
569586
process::exit(1);
570587
}
571588

589+
/// If we're preparing for an edition and we *don't* find the
590+
/// `rust_2018_preview` feature, for example, in the entry point file then
591+
/// it probably means that the edition isn't actually enabled, so we can't
592+
/// actually fix anything.
593+
///
594+
/// If this is the case, issue a warning.
572595
fn warn_if_preparing_probably_inert(&self) -> CargoResult<()> {
573596
let edition = match &self.prepare_for_edition {
574597
PrepareFor::Edition(s) => s,

src/cargo/util/diagnostic_server.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ pub enum Message {
4848
file: String,
4949
edition: String,
5050
},
51+
IdiomEditionMismatch {
52+
file: String,
53+
idioms: String,
54+
edition: Option<String>,
55+
},
5156
}
5257

5358
impl Message {
@@ -78,6 +83,7 @@ pub struct DiagnosticPrinter<'a> {
7883
config: &'a Config,
7984
preview_not_found: HashSet<String>,
8085
edition_already_enabled: HashSet<String>,
86+
idiom_mismatch: HashSet<String>,
8187
}
8288

8389
impl<'a> DiagnosticPrinter<'a> {
@@ -86,6 +92,7 @@ impl<'a> DiagnosticPrinter<'a> {
8692
config,
8793
preview_not_found: HashSet::new(),
8894
edition_already_enabled: HashSet::new(),
95+
idiom_mismatch: HashSet::new(),
8996
}
9097
}
9198

@@ -172,8 +179,32 @@ information about transitioning to the {0} edition see:
172179
self.config.shell().error(&msg)?;
173180
Ok(())
174181
}
175-
}
182+
Message::IdiomEditionMismatch { file, idioms, edition } => {
183+
// Same as above
184+
if !self.idiom_mismatch.insert(file.clone()) {
185+
return Ok(())
186+
}
187+
self.config.shell().error(&format!(
188+
"\
189+
cannot migrate to the idioms of the {} edition for `{}`
190+
because it is compiled {}, which doesn't match {0}
191+
192+
consider migrating to the {0} edition by adding `edition = '{0}'` to
193+
`Cargo.toml` and then rerunning this command; a more detailed transition
194+
guide can be found at
176195
196+
https://rust-lang-nursery.github.io/edition-guide/editions/transitioning.html
197+
",
198+
idioms,
199+
file,
200+
match edition {
201+
Some(s) => format!("with the {} edition", s),
202+
None => format!("without an edition"),
203+
},
204+
))?;
205+
Ok(())
206+
}
207+
}
177208
}
178209
}
179210

tests/testsuite/fix.rs

+56
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,62 @@ fn fix_overlapping() {
966966
assert!(contents.contains("crate::foo::<crate::A>()"));
967967
}
968968

969+
#[test]
970+
fn fix_idioms() {
971+
if !is_nightly() {
972+
return
973+
}
974+
let p = project()
975+
.file(
976+
"Cargo.toml",
977+
r#"
978+
cargo-features = ['edition']
979+
[package]
980+
name = 'foo'
981+
version = '0.1.0'
982+
edition = '2018'
983+
"#,
984+
)
985+
.file(
986+
"src/lib.rs",
987+
r#"
988+
use std::any::Any;
989+
pub fn foo() {
990+
let _x: Box<Any> = Box::new(3);
991+
}
992+
"#
993+
)
994+
.build();
995+
996+
let stderr = "\
997+
[CHECKING] foo [..]
998+
[FIXING] src/lib.rs (1 fix)
999+
[FINISHED] [..]
1000+
";
1001+
assert_that(
1002+
p.cargo("fix --edition-idioms --allow-no-vcs")
1003+
.masquerade_as_nightly_cargo(),
1004+
execs()
1005+
.with_stderr(stderr)
1006+
.with_status(0),
1007+
);
1008+
1009+
assert!(p.read_file("src/lib.rs").contains("Box<dyn Any>"));
1010+
}
1011+
1012+
#[test]
1013+
fn idioms_2015_ok() {
1014+
let p = project()
1015+
.file("src/lib.rs", "")
1016+
.build();
1017+
1018+
assert_that(
1019+
p.cargo("fix --edition-idioms --allow-no-vcs")
1020+
.masquerade_as_nightly_cargo(),
1021+
execs().with_status(0),
1022+
);
1023+
}
1024+
9691025
#[test]
9701026
fn both_edition_migrate_flags() {
9711027
if !is_nightly() {

0 commit comments

Comments
 (0)