<commit_before>// http://rosettacode.org/wiki/Array_concatenation

fn main() {
    let a_vec: Vec<i32> = vec![1, 2, 3, 4, 5];
    let b_vec: Vec<i32> = vec![6; 5];

    assert!(a_vec[0] == 1i32);
    assert!(b_vec[0] == 6i32);

    let c_vec = concatenate_arrays::<i32>(a_vec.as_slice(), b_vec.as_slice());

    println!("{:?} ~ {:?} => {:?}", a_vec, b_vec, c_vec);
}

fn concatenate_arrays<T: Clone>(x: &[T], y: &[T]) -> Vec<T> {
    let mut concat: Vec<T> = vec![x[0].clone(); x.len()];

    concat.clone_from_slice(x);
    concat.extend_from_slice(y);

    concat
}

#[cfg(test)]
mod tests {
    use super::concatenate_arrays;

    #[derive(Clone, Debug, PartialEq)]
    struct Dummy {
        a: f64,
        b: &'static str,
    }

    #[test]
    fn test_concatenation_int() {
        let a_vec: Vec<u64> = vec![0, 1, 2, 3, 4];
        let b_vec: Vec<u64> = vec![5; 5];
        let c_vec = concatenate_arrays::<u64>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec, [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]);
    }

    #[test]
    fn test_concatenation_str() {
        let a_vec: Vec<&str> = vec!["hay", "ye", "eye", "owe", "you"];
        let b_vec: Vec<&str> = vec!["why"];
        let c_vec = concatenate_arrays::<&str>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec, ["hay", "ye", "eye", "owe", "you", "why"]);
    }

    #[test]
    fn test_concatenation_tuple() {
        let a_vec: Vec<(i32, &str)> = vec![(0, "hay"), (1, "ye"), (2, "eye")];
        let b_vec: Vec<(i32, &str)> = vec![(3, "owe"), (4, "you")];
        let c_vec = concatenate_arrays::<(i32, &str)>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec, [(0, "hay"), (1, "ye"), (2, "eye"), (3, "owe"), (4, "you")]);
    }

    #[test]
    fn test_concatenation_struct() {
        let a_vec: Vec<Dummy> = vec![
            Dummy { a: 0.0, b: "hay"},
            Dummy { a: 1.1, b: "ye"},
            Dummy { a: 2.2, b: "eye"}
        ];
        let b_vec: Vec<Dummy> = vec![
            Dummy { a: 3.3, b: "owe"},
            Dummy { a: 4.4, b: "you"},
        ];

        let c_vec = concatenate_arrays::<Dummy>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec, [
            Dummy { a: 0.0, b: "hay"},
            Dummy { a: 1.1, b: "ye"},
            Dummy { a: 2.2, b: "eye"},
            Dummy { a: 3.3, b: "owe"},
            Dummy { a: 4.4, b: "you"},
        ]);
    }
}<commit_msg>rustfmt<commit_after>// http://rosettacode.org/wiki/Array_concatenation

fn main() {
    let a_vec: Vec<i32> = vec![1, 2, 3, 4, 5];
    let b_vec: Vec<i32> = vec![6; 5];

    assert!(a_vec[0] == 1i32);
    assert!(b_vec[0] == 6i32);

    let c_vec = concatenate_arrays::<i32>(a_vec.as_slice(), b_vec.as_slice());

    println!("{:?} ~ {:?} => {:?}", a_vec, b_vec, c_vec);
}

fn concatenate_arrays<T: Clone>(x: &[T], y: &[T]) -> Vec<T> {
    let mut concat: Vec<T> = vec![x[0].clone(); x.len()];

    concat.clone_from_slice(x);
    concat.extend_from_slice(y);

    concat
}

#[cfg(test)]
mod tests {
    use super::concatenate_arrays;

    #[derive(Clone, Debug, PartialEq)]
    struct Dummy {
        a: f64,
        b: &'static str,
    }

    #[test]
    fn test_concatenation_int() {
        let a_vec: Vec<u64> = vec![0, 1, 2, 3, 4];
        let b_vec: Vec<u64> = vec![5; 5];
        let c_vec = concatenate_arrays::<u64>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec, [0, 1, 2, 3, 4, 5, 5, 5, 5, 5]);
    }

    #[test]
    fn test_concatenation_str() {
        let a_vec: Vec<&str> = vec!["hay", "ye", "eye", "owe", "you"];
        let b_vec: Vec<&str> = vec!["why"];
        let c_vec = concatenate_arrays::<&str>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec, ["hay", "ye", "eye", "owe", "you", "why"]);
    }

    #[test]
    fn test_concatenation_tuple() {
        let a_vec: Vec<(i32, &str)> = vec![(0, "hay"), (1, "ye"), (2, "eye")];
        let b_vec: Vec<(i32, &str)> = vec![(3, "owe"), (4, "you")];
        let c_vec = concatenate_arrays::<(i32, &str)>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec,
                   [(0, "hay"), (1, "ye"), (2, "eye"), (3, "owe"), (4, "you")]);
    }

    #[test]
    fn test_concatenation_struct() {
        let a_vec: Vec<Dummy> = vec![Dummy { a: 0.0, b: "hay" },
                                     Dummy { a: 1.1, b: "ye" },
                                     Dummy { a: 2.2, b: "eye" }];
        let b_vec: Vec<Dummy> = vec![Dummy { a: 3.3, b: "owe" }, Dummy { a: 4.4, b: "you" }];

        let c_vec = concatenate_arrays::<Dummy>(a_vec.as_slice(), b_vec.as_slice());

        assert_eq!(c_vec,
                   [Dummy { a: 0.0, b: "hay" },
                    Dummy { a: 1.1, b: "ye" },
                    Dummy { a: 2.2, b: "eye" },
                    Dummy { a: 3.3, b: "owe" },
                    Dummy { a: 4.4, b: "you" }]);
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, SubCommand};

static SC_VISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2
Some help

USAGE:
    ct test [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag        [aliases: v_flg, flag2, flg3]
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --opt <opt>     [aliases: visible]";

static SC_INVISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2
Some help

USAGE:
    ct test [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --opt <opt>    ";

#[test]
fn single_alias_of_option() {
    let a = App::new("single_alias")
        .arg(Arg::with_name("alias")
            .long("alias")
            .takes_value(true)
            .help("single alias")
            .alias("new-opt"))
        .get_matches_from_safe(vec![
            "", "--new-opt", "cool"
        ]);
    assert!(a.is_ok());
    let a = a.unwrap();
    assert!(a.is_present("alias"));
    assert_eq!(a.value_of("alias").unwrap(), "cool");
}

#[test]
fn multiple_aliases_of_option() {
    let a = App::new("multiple_aliases")
        .arg(Arg::with_name("aliases")
            .long("aliases")
            .takes_value(true)
            .help("multiple aliases")
            .aliases(&vec![
                "alias1",
                "alias2",
                "alias3"
        ]));
    let long = a.clone().get_matches_from_safe(vec![
        "", "--aliases", "value"
    ]);
    assert!(long.is_ok());
    let long = long.unwrap();

    let als1 = a.clone().get_matches_from_safe(vec![
        "", "--alias1", "value"
    ]);
    assert!(als1.is_ok());
    let als1 = als1.unwrap();

    let als2 = a.clone().get_matches_from_safe(vec![
        "", "--alias2", "value"
    ]);
    assert!(als2.is_ok());
    let als2 = als2.unwrap();

    let als3 = a.clone().get_matches_from_safe(vec![
        "", "--alias3", "value"
    ]);
    assert!(als3.is_ok());
    let als3 = als3.unwrap();

    assert!(long.is_present("aliases"));
    assert!(als1.is_present("aliases"));
    assert!(als2.is_present("aliases"));
    assert!(als3.is_present("aliases"));
    assert_eq!(long.value_of("aliases").unwrap(), "value");
    assert_eq!(als1.value_of("aliases").unwrap(), "value");
    assert_eq!(als2.value_of("aliases").unwrap(), "value");
    assert_eq!(als3.value_of("aliases").unwrap(), "value");
}

#[test]
fn single_alias_of_flag() {
    let a = App::new("test")
                .arg(Arg::with_name("flag")
                    .long("flag")
                    .alias("alias"))
                .get_matches_from_safe(vec!["", "--alias"]);
    assert!(a.is_ok());
    let a = a.unwrap();
    assert!(a.is_present("flag"));
}

#[test]
fn multiple_aliases_of_flag() {
    let a = App::new("test")
                .arg(Arg::with_name("flag")
                    .long("flag")
                    .aliases(&["invisible",
                        "set", "of",
                        "cool", "aliases"]));

    let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]);
    assert!(flag.is_ok());
    let flag = flag.unwrap();

    let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]);
    assert!(inv.is_ok());
    let inv = inv.unwrap();

    let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]);
    assert!(cool.is_ok());
    let cool = cool.unwrap();

    let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]);
    assert!(als.is_ok());
    let als = als.unwrap();

    assert!(flag.is_present("flag"));
    assert!(inv.is_present("flag"));
    assert!(cool.is_present("flag"));
    assert!(als.is_present("flag"));
}

#[test]
fn alias_on_a_subcommand_option() {
    let m = App::new("test")
        .subcommand(SubCommand::with_name("some")
            .arg(Arg::with_name("test")
                .short("t")
                .long("test")
                .takes_value(true)
                .alias("opt")
                .help("testing testing")))
        .arg(Arg::with_name("other")
            .long("other")
            .aliases(&vec!["o1", "o2", "o3"]))
        .get_matches_from(vec![
            "test", "some", "--opt", "awesome"
        ]);

    assert!(m.subcommand_matches("some").is_some());
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "awesome");
}

#[test]
fn invisible_arg_aliases_help_output() {
    let app = App::new("ct")
    .author("Salim Afiune")
        .subcommand(SubCommand::with_name("test")
            .about("Some help")
            .version("1.2")
            .arg(Arg::with_name("opt")
                .long("opt")
                .short("o")
                .takes_value(true)
                .aliases(&["invisible", "als1", "more"]))
            .arg(Arg::from_usage("-f, --flag")
                .aliases(&["invisible", "flg1", "anyway"])));
    assert!(test::compare_output(app, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false));
}

#[test]
fn visible_arg_aliases_help_output() {
    let app = App::new("ct")
        .author("Salim Afiune")
        .subcommand(SubCommand::with_name("test")
            .about("Some help")
            .version("1.2")
            .arg(Arg::with_name("opt")
                .long("opt")
                .short("o")
                .takes_value(true)
                .alias("invisible")
                .visible_alias("visible"))
            .arg(Arg::with_name("flg")
                .long("flag")
                .short("f")
                .visible_aliases(&["v_flg", "flag2", "flg3"])));
    assert!(test::compare_output(app, "ct test --help", SC_VISIBLE_ALIAS_HELP, false));
}
<commit_msg>chore(clippy): Fix useless_vec warnings.<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, SubCommand};

static SC_VISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2
Some help

USAGE:
    ct test [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag        [aliases: v_flg, flag2, flg3]
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --opt <opt>     [aliases: visible]";

static SC_INVISIBLE_ALIAS_HELP: &'static str = "ct-test 1.2
Some help

USAGE:
    ct test [FLAGS] [OPTIONS]

FLAGS:
    -f, --flag
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -o, --opt <opt>    ";

#[test]
fn single_alias_of_option() {
    let a = App::new("single_alias")
        .arg(Arg::with_name("alias")
            .long("alias")
            .takes_value(true)
            .help("single alias")
            .alias("new-opt"))
        .get_matches_from_safe(vec![
            "", "--new-opt", "cool"
        ]);
    assert!(a.is_ok());
    let a = a.unwrap();
    assert!(a.is_present("alias"));
    assert_eq!(a.value_of("alias").unwrap(), "cool");
}

#[test]
fn multiple_aliases_of_option() {
    let a = App::new("multiple_aliases")
        .arg(Arg::with_name("aliases")
            .long("aliases")
            .takes_value(true)
            .help("multiple aliases")
            .aliases(&[
                "alias1",
                "alias2",
                "alias3"
        ]));
    let long = a.clone().get_matches_from_safe(vec![
        "", "--aliases", "value"
    ]);
    assert!(long.is_ok());
    let long = long.unwrap();

    let als1 = a.clone().get_matches_from_safe(vec![
        "", "--alias1", "value"
    ]);
    assert!(als1.is_ok());
    let als1 = als1.unwrap();

    let als2 = a.clone().get_matches_from_safe(vec![
        "", "--alias2", "value"
    ]);
    assert!(als2.is_ok());
    let als2 = als2.unwrap();

    let als3 = a.clone().get_matches_from_safe(vec![
        "", "--alias3", "value"
    ]);
    assert!(als3.is_ok());
    let als3 = als3.unwrap();

    assert!(long.is_present("aliases"));
    assert!(als1.is_present("aliases"));
    assert!(als2.is_present("aliases"));
    assert!(als3.is_present("aliases"));
    assert_eq!(long.value_of("aliases").unwrap(), "value");
    assert_eq!(als1.value_of("aliases").unwrap(), "value");
    assert_eq!(als2.value_of("aliases").unwrap(), "value");
    assert_eq!(als3.value_of("aliases").unwrap(), "value");
}

#[test]
fn single_alias_of_flag() {
    let a = App::new("test")
                .arg(Arg::with_name("flag")
                    .long("flag")
                    .alias("alias"))
                .get_matches_from_safe(vec!["", "--alias"]);
    assert!(a.is_ok());
    let a = a.unwrap();
    assert!(a.is_present("flag"));
}

#[test]
fn multiple_aliases_of_flag() {
    let a = App::new("test")
                .arg(Arg::with_name("flag")
                    .long("flag")
                    .aliases(&["invisible",
                        "set", "of",
                        "cool", "aliases"]));

    let flag = a.clone().get_matches_from_safe(vec!["", "--flag"]);
    assert!(flag.is_ok());
    let flag = flag.unwrap();

    let inv = a.clone().get_matches_from_safe(vec!["", "--invisible"]);
    assert!(inv.is_ok());
    let inv = inv.unwrap();

    let cool = a.clone().get_matches_from_safe(vec!["", "--cool"]);
    assert!(cool.is_ok());
    let cool = cool.unwrap();

    let als = a.clone().get_matches_from_safe(vec!["", "--aliases"]);
    assert!(als.is_ok());
    let als = als.unwrap();

    assert!(flag.is_present("flag"));
    assert!(inv.is_present("flag"));
    assert!(cool.is_present("flag"));
    assert!(als.is_present("flag"));
}

#[test]
fn alias_on_a_subcommand_option() {
    let m = App::new("test")
        .subcommand(SubCommand::with_name("some")
            .arg(Arg::with_name("test")
                .short("t")
                .long("test")
                .takes_value(true)
                .alias("opt")
                .help("testing testing")))
        .arg(Arg::with_name("other")
            .long("other")
            .aliases(&["o1", "o2", "o3"]))
        .get_matches_from(vec![
            "test", "some", "--opt", "awesome"
        ]);

    assert!(m.subcommand_matches("some").is_some());
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "awesome");
}

#[test]
fn invisible_arg_aliases_help_output() {
    let app = App::new("ct")
    .author("Salim Afiune")
        .subcommand(SubCommand::with_name("test")
            .about("Some help")
            .version("1.2")
            .arg(Arg::with_name("opt")
                .long("opt")
                .short("o")
                .takes_value(true)
                .aliases(&["invisible", "als1", "more"]))
            .arg(Arg::from_usage("-f, --flag")
                .aliases(&["invisible", "flg1", "anyway"])));
    assert!(test::compare_output(app, "ct test --help", SC_INVISIBLE_ALIAS_HELP, false));
}

#[test]
fn visible_arg_aliases_help_output() {
    let app = App::new("ct")
        .author("Salim Afiune")
        .subcommand(SubCommand::with_name("test")
            .about("Some help")
            .version("1.2")
            .arg(Arg::with_name("opt")
                .long("opt")
                .short("o")
                .takes_value(true)
                .alias("invisible")
                .visible_alias("visible"))
            .arg(Arg::with_name("flg")
                .long("flag")
                .short("f")
                .visible_aliases(&["v_flg", "flag2", "flg3"])));
    assert!(test::compare_output(app, "ct test --help", SC_VISIBLE_ALIAS_HELP, false));
}
<|endoftext|>


<commit_before>#![feature(slice_concat_ext, custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::slice::SliceConcatExt;
use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp {
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    flags.push("--edition 2018".to_owned());
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    let mut config = mk_config("compile-fail");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    flags.push("--edition 2018".to_owned());
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    let mut config = mk_config("ui");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

/// Ensures that the `MIRI_SYSROOT` env var is set.
fn set_sysroot() {
    if std::env::var("MIRI_SYSROOT").is_ok() {
        // Nothing to do.
        return;
    }
    let sysroot = std::process::Command::new("rustc")
        .arg("--print")
        .arg("sysroot")
        .output()
        .expect("rustc not found")
        .stdout;
    let sysroot = String::from_utf8(sysroot).expect("sysroot is not utf8");
    std::env::set_var("MIRI_SYSROOT", sysroot.trim());
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    set_sysroot();

    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<commit_msg>compiletest can just propagate MIRI_SYSROOT from the outside<commit_after>#![feature(slice_concat_ext, custom_test_frameworks)]
// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest.
#![test_runner(test_runner)]

use std::slice::SliceConcatExt;
use std::path::PathBuf;
use std::env;

use compiletest_rs as compiletest;
use colored::*;

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp {
    let mut config = compiletest::Config::default().tempdir();
    config.mode = mode.parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.filter = env::args().nth(1);
    config.host = get_host();
    config
}

fn compile_fail(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running compile-fail tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    flags.push("--edition 2018".to_owned());
    if opt {
        // Optimizing too aggressivley makes UB detection harder, but test at least
        // the default value.
        // FIXME: Opt level 3 ICEs during stack trace generation.
        flags.push("-Zmir-opt-level=1".to_owned());
    }

    let mut config = mk_config("compile-fail");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!("{}", format!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    ).green().bold());

    let mut flags = Vec::new();
    flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs
    flags.push("--edition 2018".to_owned());
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    }

    let mut config = mk_config("ui");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.target_rustcflags = Some(flags.join(" "));
    compiletest::run_tests(&config);
}

fn get_host() -> String {
    let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc"));
    let rustc_version = std::process::Command::new(rustc)
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8");
    let version_meta = rustc_version::version_meta_for(&rustc_version)
        .expect("failed to parse rustc version info");
    version_meta.host
}

fn get_target() -> String {
    std::env::var("MIRI_TARGET").unwrap_or_else(|_| get_host())
}

fn run_pass_miri(opt: bool) {
    miri_pass("tests/run-pass", &get_target(), opt);
}

fn compile_fail_miri(opt: bool) {
    compile_fail("tests/compile-fail", &get_target(), opt);
}

fn test_runner(_tests: &[&()]) {
    run_pass_miri(false);
    run_pass_miri(true);

    compile_fail_miri(false);
    compile_fail_miri(true);
}
<|endoftext|>


<commit_before>use std::iter;

use ast::edit::IndentLevel;
use ide_db::base_db::AnchoredPathBuf;
use itertools::Itertools;
use stdx::format_to;
use syntax::{
    ast::{self, edit::AstNodeEdit, HasName},
    AstNode, TextRange,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: move_module_to_file
//
// Moves inline module's contents to a separate file.
//
// ```
// mod $0foo {
//     fn t() {}
// }
// ```
// ->
// ```
// mod foo;
// ```
pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
    let module_items = module_ast.item_list()?;

    let l_curly_offset = module_items.syntax().text_range().start();
    if l_curly_offset <= ctx.offset() {
        cov_mark::hit!(available_before_curly);
        return None;
    }
    let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);

    let module_name = module_ast.name()?;

    // get to the outermost module syntax so we can grab the module of file we are in
    let outermost_mod_decl =
        iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
    let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
    let parent_module = module_def.parent(ctx.db())?;

    acc.add(
        AssistId("move_module_to_file", AssistKind::RefactorExtract),
        "Extract module to file",
        target,
        |builder| {
            let path = {
                let mut buf = String::from("./");
                match parent_module.name(ctx.db()) {
                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
                        format_to!(buf, "{}/", name)
                    }
                    _ => (),
                }
                let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
                    .filter_map(|it| it.name())
                    .collect::<Vec<_>>();
                format_to!(buf, "{}", segments.into_iter().rev().format("/"));
                format_to!(buf, ".rs");
                buf
            };
            let contents = {
                let items = module_items.dedent(IndentLevel(1)).to_string();
                let mut items =
                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
                if !items.is_empty() {
                    items.push('\n');
                }
                items
            };

            let buf = format!("mod {};", module_name);

            let replacement_start = match module_ast.mod_token() {
                Some(mod_token) => mod_token.text_range(),
                None => module_ast.syntax().text_range(),
            }
            .start();

            builder.replace(
                TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
                buf,
            );

            let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
            builder.create_file(dst, contents);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn extract_from_root() {
        check_assist(
            move_module_to_file,
            r#"
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_from_submodule() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submod;
//- /submod.rs
$0mod inner {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submod.rs
mod inner;
fn g() {}
//- /submod/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submodule;
//- /submodule/mod.rs
mod inner$0 {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submodule/mod.rs
mod inner;
fn g() {}
//- /submodule/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_public() {
        check_assist(
            move_module_to_file,
            r#"
pub mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_public_crate() {
        check_assist(
            move_module_to_file,
            r#"
pub(crate) mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub(crate) mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn available_before_curly() {
        cov_mark::check!(available_before_curly);
        check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
    }

    #[test]
    fn keep_outer_comments_and_attributes() {
        check_assist(
            move_module_to_file,
            r#"
/// doc comment
#[attribute]
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
/// doc comment
#[attribute]
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_nested() {
        check_assist(
            move_module_to_file,
            r#"
//- /lib.rs
mod foo;
//- /foo.rs
mod bar {
    mod baz {
        mod qux$0 {}
    }
}
"#,
            r#"
//- /foo.rs
mod bar {
    mod baz {
        mod qux;
    }
}
//- /foo/bar/baz/qux.rs
"#,
        );
    }
}
<commit_msg>Auto merge of #12089 - lowr:fix/move-raw-ident-module-to-file, r=jonas-schievink<commit_after>use std::iter;

use ast::edit::IndentLevel;
use ide_db::base_db::AnchoredPathBuf;
use itertools::Itertools;
use stdx::format_to;
use syntax::{
    ast::{self, edit::AstNodeEdit, HasName},
    AstNode, SmolStr, TextRange,
};

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: move_module_to_file
//
// Moves inline module's contents to a separate file.
//
// ```
// mod $0foo {
//     fn t() {}
// }
// ```
// ->
// ```
// mod foo;
// ```
pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
    let module_items = module_ast.item_list()?;

    let l_curly_offset = module_items.syntax().text_range().start();
    if l_curly_offset <= ctx.offset() {
        cov_mark::hit!(available_before_curly);
        return None;
    }
    let target = TextRange::new(module_ast.syntax().text_range().start(), l_curly_offset);

    let module_name = module_ast.name()?;

    // get to the outermost module syntax so we can grab the module of file we are in
    let outermost_mod_decl =
        iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
    let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
    let parent_module = module_def.parent(ctx.db())?;

    acc.add(
        AssistId("move_module_to_file", AssistKind::RefactorExtract),
        "Extract module to file",
        target,
        |builder| {
            let path = {
                let mut buf = String::from("./");
                match parent_module.name(ctx.db()) {
                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
                        format_to!(buf, "{}/", name)
                    }
                    _ => (),
                }
                let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
                    .filter_map(|it| it.name())
                    .map(|name| SmolStr::from(name.text().trim_start_matches("r#")))
                    .collect::<Vec<_>>();

                format_to!(buf, "{}", segments.into_iter().rev().format("/"));

                // We need to special case mod named `r#mod` and place the file in a
                // subdirectory as "mod.rs" would be of its parent module otherwise.
                if module_name.text() == "r#mod" {
                    format_to!(buf, "/mod.rs");
                } else {
                    format_to!(buf, ".rs");
                }
                buf
            };
            let contents = {
                let items = module_items.dedent(IndentLevel(1)).to_string();
                let mut items =
                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
                if !items.is_empty() {
                    items.push('\n');
                }
                items
            };

            let buf = format!("mod {};", module_name);

            let replacement_start = match module_ast.mod_token() {
                Some(mod_token) => mod_token.text_range(),
                None => module_ast.syntax().text_range(),
            }
            .start();

            builder.replace(
                TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
                buf,
            );

            let dst = AnchoredPathBuf { anchor: ctx.file_id(), path };
            builder.create_file(dst, contents);
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn extract_from_root() {
        check_assist(
            move_module_to_file,
            r#"
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_from_submodule() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submod;
//- /submod.rs
$0mod inner {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submod.rs
mod inner;
fn g() {}
//- /submod/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod submodule;
//- /submodule/mod.rs
mod inner$0 {
    fn f() {}
}
fn g() {}
"#,
            r#"
//- /submodule/mod.rs
mod inner;
fn g() {}
//- /submodule/inner.rs
fn f() {}
"#,
        );
    }

    #[test]
    fn extract_public() {
        check_assist(
            move_module_to_file,
            r#"
pub mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_public_crate() {
        check_assist(
            move_module_to_file,
            r#"
pub(crate) mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
pub(crate) mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn available_before_curly() {
        cov_mark::check!(available_before_curly);
        check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
    }

    #[test]
    fn keep_outer_comments_and_attributes() {
        check_assist(
            move_module_to_file,
            r#"
/// doc comment
#[attribute]
mod $0tests {
    #[test] fn t() {}
}
"#,
            r#"
//- /main.rs
/// doc comment
#[attribute]
mod tests;
//- /tests.rs
#[test] fn t() {}
"#,
        );
    }

    #[test]
    fn extract_nested() {
        check_assist(
            move_module_to_file,
            r#"
//- /lib.rs
mod foo;
//- /foo.rs
mod bar {
    mod baz {
        mod qux$0 {}
    }
}
"#,
            r#"
//- /foo.rs
mod bar {
    mod baz {
        mod qux;
    }
}
//- /foo/bar/baz/qux.rs
"#,
        );
    }

    #[test]
    fn extract_mod_with_raw_ident() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod $0r#static {}
"#,
            r#"
//- /main.rs
mod r#static;
//- /static.rs
"#,
        )
    }

    #[test]
    fn extract_r_mod() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod $0r#mod {}
"#,
            r#"
//- /main.rs
mod r#mod;
//- /mod/mod.rs
"#,
        )
    }

    #[test]
    fn extract_r_mod_from_mod_rs() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod foo;
//- /foo/mod.rs
mod $0r#mod {}
"#,
            r#"
//- /foo/mod.rs
mod r#mod;
//- /foo/mod/mod.rs
"#,
        )
    }

    #[test]
    fn extract_nested_r_mod() {
        check_assist(
            move_module_to_file,
            r#"
//- /main.rs
mod r#mod {
    mod foo {
        mod $0r#mod {}
    }
}
"#,
            r#"
//- /main.rs
mod r#mod {
    mod foo {
        mod r#mod;
    }
}
//- /mod/foo/mod/mod.rs
"#,
        )
    }
}
<|endoftext|>


<commit_before>use std::iter::once;

use syntax::{
    ast::{
        self,
        edit::{AstNodeEdit, IndentLevel},
        make, HasLoopBody,
    },
    AstNode, T,
};

use crate::{
    assist_context::{AssistContext, Assists},
    utils::invert_boolean_expression,
    AssistId, AssistKind,
};

// Assist: convert_while_to_loop
//
// Replace a while with a loop.
//
// ```
// fn main() {
//     $0while cond {
//         foo();
//     }
// }
// ```
// ->
// ```
// fn main() {
//     loop {
//         if !cond {
//             break;
//         }
//         foo();
//     }
// }
// ```
pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let while_kw = ctx.find_token_syntax_at_offset(T![while])?;
    let while_expr: ast::WhileExpr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
    let while_body = while_expr.loop_body()?;
    let cond = while_expr.condition()?;

    // Don't handle while let
    if cond.pat().is_some() {
        return None;
    };

    let cond_expr = cond.expr()?;

    let target = while_expr.syntax().text_range();
    acc.add(
        AssistId("convert_while_to_loop", AssistKind::RefactorRewrite),
        "Convert while to loop",
        target,
        |edit| {
            let while_indent_level = IndentLevel::from_node(while_expr.syntax());

            let replacement = {
                let if_expr = {
                    let cond = invert_boolean_expression(cond_expr);
                    let then_branch = make::block_expr(
                        once(make::expr_stmt(make::expr_break(None)).into()),
                        None,
                    );

                    make::expr_if(make::condition(cond, None), then_branch, None)
                };

                let if_expr = if_expr.indent(while_indent_level);
                let stmts = once(make::expr_stmt(if_expr).into()).chain(while_body.statements());

                let block_expr = make::block_expr(stmts, while_body.tail_expr());

                let block_expr = block_expr.indent(while_indent_level);

                make::expr_loop(block_expr)
            };

            edit.replace(target, replacement.syntax().text())
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn convert_inside_fn() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 cond {
        foo();
    }
}
"#,
            r#"
fn main() {
    loop {
        if !cond {
            break;
        }
        foo();
    }
}
"#,
        );
    }

    #[test]
    fn convert_busy_wait() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 cond() {}
}
"#,
            r#"
fn main() {
    loop {
        if !cond() {
            break;
        }
    }
}
"#,
        );
    }

    #[test]
    fn convert_trailing_expr() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 cond() {
        bar()
    }
}
"#,
            r#"
fn main() {
    loop {
        if !cond() {
            break;
        }
        bar()
    }
}
"#,
        );
    }

    #[test]
    fn ignore_while_let() {
        check_assist_not_applicable(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 let Some(_) = foo() {
        bar();
    }
}
"#,
        );
    }

    #[test]
    fn ignore_cursor_in_body() {
        check_assist_not_applicable(
            convert_while_to_loop,
            r#"
fn main() {
    while cond {$0
        bar();
    }
}
"#,
        );
    }
}
<commit_msg>feat: handle while let to loop<commit_after>use std::iter::once;

use syntax::{
    ast::{
        self,
        edit::{AstNodeEdit, IndentLevel},
        make, HasLoopBody,
    },
    AstNode, T,
};

use crate::{
    assist_context::{AssistContext, Assists},
    utils::invert_boolean_expression,
    AssistId, AssistKind,
};

// Assist: convert_while_to_loop
//
// Replace a while with a loop.
//
// ```
// fn main() {
//     $0while cond {
//         foo();
//     }
// }
// ```
// ->
// ```
// fn main() {
//     loop {
//         if !cond {
//             break;
//         }
//         foo();
//     }
// }
// ```
pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let while_kw = ctx.find_token_syntax_at_offset(T![while])?;
    let while_expr = while_kw.parent().and_then(ast::WhileExpr::cast)?;
    let while_body = while_expr.loop_body()?;
    let while_cond = while_expr.condition()?;

    let if_cond = match while_cond.pat() {
        Some(_) => while_expr.condition()?,
        None => make::condition(invert_boolean_expression(while_cond.expr()?), None),
    };
    let target = while_expr.syntax().text_range();
    acc.add(
        AssistId("convert_while_to_loop", AssistKind::RefactorRewrite),
        "Convert while to loop",
        target,
        |edit| {
            let while_indent_level = IndentLevel::from_node(while_expr.syntax());

            let break_block =
                make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
                    .indent(while_indent_level);
            let block_expr = match while_cond.pat() {
                Some(_) => {
                    let if_expr = make::expr_if(if_cond, while_body, Some(break_block.into()));
                    let stmts = once(make::expr_stmt(if_expr).into());
                    make::block_expr(stmts, None)
                }
                None => {
                    let if_expr = make::expr_if(if_cond, break_block, None);
                    let stmts =
                        once(make::expr_stmt(if_expr).into()).chain(while_body.statements());
                    make::block_expr(stmts, while_body.tail_expr())
                }
            };

            let replacement = make::expr_loop(block_expr.indent(while_indent_level));
            edit.replace(target, replacement.syntax().text())
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn convert_inside_fn() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 cond {
        foo();
    }
}
"#,
            r#"
fn main() {
    loop {
        if !cond {
            break;
        }
        foo();
    }
}
"#,
        );
    }

    #[test]
    fn convert_busy_wait() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 cond() {}
}
"#,
            r#"
fn main() {
    loop {
        if !cond() {
            break;
        }
    }
}
"#,
        );
    }

    #[test]
    fn convert_trailing_expr() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 cond() {
        bar()
    }
}
"#,
            r#"
fn main() {
    loop {
        if !cond() {
            break;
        }
        bar()
    }
}
"#,
        );
    }

    #[test]
    fn convert_while_let() {
        check_assist(
            convert_while_to_loop,
            r#"
fn main() {
    while$0 let Some(_) = foo() {
        bar();
    }
}
"#,
            r#"
fn main() {
    loop {
        if let Some(_) = foo() {
            bar();
        } else {
            break;
        }
    }
}
"#,
        );
    }

    #[test]
    fn ignore_cursor_in_body() {
        check_assist_not_applicable(
            convert_while_to_loop,
            r#"
fn main() {
    while cond {$0
        bar();
    }
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::hir::*;
use utils::{paths, method_chain_args, span_help_and_lint, match_type};

/// **What it does:*** Checks for unnecessary `ok()` in if let.
///
/// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match on `Ok(x`
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rustc
/// for result in iter {
///     if let Some(bench) = try!(result).parse().ok() {
///         vec.push(bench)
///     }
/// }
/// ```
declare_lint! {
    pub IF_LET_SOME_RESULT,
    Warn,
    "usage of `ok()` in `if let Some(x)` statements is unnecessary, match on `Ok(expr)` instead"
}

#[derive(Copy, Clone)]
pub struct OkIfLetPass;

impl LintPass for OkIfLetPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(IF_LET_SOME_RESULT)
    }
}

impl LateLintPass for OkIfLetPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if_let_chain! {[ //begin checking variables
            let ExprMatch(ref op, ref body, ref source) = expr.node, //test if expr is a match
            let MatchSource::IfLetDesugar { contains_else_clause: _ } = *source, //test if it is an If Let
            let ExprMethodCall(_, _, ref result_types) = op.node, //check is expr.ok() has type Result<T,E>.ok()
            let PatKind::TupleStruct(ref x, ref y, _)  = body[0].pats[0].node, //get operation
            let Some(_) = method_chain_args(op, &["ok"]) //test to see if using ok() methoduse std::marker::Sized;

        ], {
            let is_result_type = match_type(cx, cx.tcx.expr_ty(&result_types[0]), &paths::RESULT);
            let some_expr_string = print::pat_to_string(&y[0]);
            if print::path_to_string(x) == "Some" && is_result_type {
                span_help_and_lint(cx, IF_LET_SOME_RESULT, expr.span,
                "Matching on `Some` with `ok()` is redundant",
                &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string));
            }
        }}
    }
}
<commit_msg>fixed struct elison<commit_after>use rustc::lint::*;
use rustc::hir::*;
use utils::{paths, method_chain_args, span_help_and_lint, match_type};

/// **What it does:*** Checks for unnecessary `ok()` in if let.
///
/// **Why is this bad?** Calling `ok()` in if let is unnecessary, instead match on `Ok(x`
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rustc
/// for result in iter {
///     if let Some(bench) = try!(result).parse().ok() {
///         vec.push(bench)
///     }
/// }
/// ```
declare_lint! {
    pub IF_LET_SOME_RESULT,
    Warn,
    "usage of `ok()` in `if let Some(x)` statements is unnecessary, match on `Ok(expr)` instead"
}

#[derive(Copy, Clone)]
pub struct OkIfLetPass;

impl LintPass for OkIfLetPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(IF_LET_SOME_RESULT)
    }
}

impl LateLintPass for OkIfLetPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if_let_chain! {[ //begin checking variables
            let ExprMatch(ref op, ref body, ref source) = expr.node, //test if expr is a match
            let MatchSource::IfLetDesugar { .. } = *source, //test if it is an If Let
            let ExprMethodCall(_, _, ref result_types) = op.node, //check is expr.ok() has type Result<T,E>.ok()
            let PatKind::TupleStruct(ref x, ref y, _)  = body[0].pats[0].node, //get operation
            let Some(_) = method_chain_args(op, &["ok"]) //test to see if using ok() methoduse std::marker::Sized;

        ], {
            let is_result_type = match_type(cx, cx.tcx.expr_ty(&result_types[0]), &paths::RESULT);
            let some_expr_string = print::pat_to_string(&y[0]);
            if print::path_to_string(x) == "Some" && is_result_type {
                span_help_and_lint(cx, IF_LET_SOME_RESULT, expr.span,
                "Matching on `Some` with `ok()` is redundant",
                &format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string));
            }
        }}
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::io::Write;
use std::path::PathBuf;

use cargo_edit::{
    colorize_stderr, find, get_latest_dependency, registry_url, resolve_manifests, set_dep_version,
    shell_note, shell_status, shell_warn, update_registry_index, CargoResult, Context, CrateSpec,
    Dependency, LocalManifest,
};
use clap::Args;
use indexmap::IndexMap;
use semver::{Op, VersionReq};
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};

/// Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).
#[derive(Debug, Args)]
#[clap(version)]
#[clap(after_help = "\
This command differs from `cargo update`, which updates the dependency versions recorded in the \
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version \
to upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io \
are supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--workspace` flag is supplied. The \
`--workspace` flag may be supplied in the presence of a virtual manifest.

If the '--to-lockfile' flag is supplied, all dependencies will be upgraded to the currently locked \
version as recorded in the Cargo.lock file. This flag requires that the Cargo.lock file is \
up-to-date. If the lock file is missing, or it needs to be updated, cargo-upgrade will exit with \
an error. If the '--to-lockfile' flag is supplied then the network won't be accessed.")]
pub struct UpgradeArgs {
    /// Crates to be upgraded.
    dependency: Vec<String>,

    /// Path to the manifest to upgrade
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    manifest_path: Option<PathBuf>,

    /// Package id of the crate to add this dependency to.
    #[clap(
        long = "package",
        short = 'p',
        value_name = "PKGID",
        conflicts_with = "all",
        conflicts_with = "workspace"
    )]
    pkgid: Vec<String>,

    /// Upgrade all packages in the workspace.
    #[clap(
        long,
        help = "[deprecated in favor of `--workspace`]",
        conflicts_with = "workspace",
        conflicts_with = "pkgid"
    )]
    all: bool,

    /// Upgrade all packages in the workspace.
    #[clap(long, conflicts_with = "all", conflicts_with = "pkgid")]
    workspace: bool,

    /// Print changes to be made without making them.
    #[clap(long)]
    dry_run: bool,

    /// Upgrade dependencies pinned in the manifest.
    #[clap(long)]
    pinned: bool,

    /// Run without accessing the network
    #[clap(long)]
    offline: bool,

    /// Upgrade all packages to the version in the lockfile.
    #[clap(long, conflicts_with = "dependency")]
    to_lockfile: bool,

    /// Crates to exclude and not upgrade.
    #[clap(long)]
    exclude: Vec<String>,

    /// Require `Cargo.toml` to be up to date
    #[clap(long)]
    locked: bool,

    /// Use verbose output
    #[clap(short, long)]
    verbose: bool,

    /// Unstable (nightly-only) flags
    #[clap(short = 'Z', value_name = "FLAG", global = true, arg_enum)]
    unstable_features: Vec<UnstableOptions>,
}

impl UpgradeArgs {
    pub fn exec(self) -> CargoResult<()> {
        exec(self)
    }

    fn workspace(&self) -> bool {
        self.all || self.workspace
    }

    fn resolve_targets(&self) -> CargoResult<Vec<cargo_metadata::Package>> {
        resolve_manifests(
            self.manifest_path.as_deref(),
            self.workspace(),
            self.pkgid.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
        )
    }

    fn verbose<F>(&self, mut callback: F) -> CargoResult<()>
    where
        F: FnMut() -> CargoResult<()>,
    {
        if self.verbose {
            callback()
        } else {
            Ok(())
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
enum UnstableOptions {}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn exec(args: UpgradeArgs) -> CargoResult<()> {
    if args.all {
        deprecated_message("The flag `--all` has been deprecated in favor of `--workspace`")?;
    }

    if !args.offline && !args.to_lockfile {
        let url = registry_url(&find(args.manifest_path.as_deref())?, None)?;
        update_registry_index(&url, false)?;
    }

    let manifests = args.resolve_targets()?;
    let locked = args
        .to_lockfile
        .then(|| load_lockfile(&manifests))
        .transpose()?
        .unwrap_or_default();

    let selected_dependencies = args
        .dependency
        .iter()
        .map(|name| {
            let spec = CrateSpec::resolve(name)?;
            Ok((spec.name, spec.version_req))
        })
        .collect::<CargoResult<IndexMap<_, _>>>()?;
    let mut processed_keys = BTreeSet::new();

    let mut updated_registries = BTreeSet::new();
    let mut any_crate_modified = false;
    let mut compatible_present = false;
    let mut pinned_present = false;
    for package in manifests {
        let mut manifest = LocalManifest::try_new(package.manifest_path.as_std_path())?;
        let mut crate_modified = false;
        let manifest_path = manifest.path.clone();
        shell_status("Checking", &format!("{}'s dependencies", package.name))?;
        for dep_table in manifest.get_dependency_tables_mut() {
            for (dep_key, dep_item) in dep_table.iter_mut() {
                let dep_key = dep_key.get();
                processed_keys.insert(dep_key.to_owned());
                if !selected_dependencies.is_empty() && !selected_dependencies.contains_key(dep_key)
                {
                    args.verbose(|| {
                        shell_warn(&format!("ignoring {}, excluded by user", dep_key))
                    })?;
                    continue;
                }
                if args.exclude.contains(&dep_key.to_owned()) {
                    args.verbose(|| {
                        shell_warn(&format!("ignoring {}, excluded by user", dep_key))
                    })?;
                    continue;
                }
                let dependency = match Dependency::from_toml(&manifest_path, dep_key, dep_item) {
                    Ok(dependency) => dependency,
                    Err(err) => {
                        shell_warn(&format!("ignoring {}, invalid entry: {}", dep_key, err))?;
                        continue;
                    }
                };
                let old_version_req = match dependency.version() {
                    Some(version_req) => version_req.to_owned(),
                    None => {
                        args.verbose(|| {
                            let source = dependency
                                .source()
                                .map(|s| s.to_string())
                                .unwrap_or_else(|| "unknown".to_owned());
                            shell_warn(&format!(
                                "ignoring {}, source is {}",
                                dependency.toml_key(),
                                source,
                            ))
                        })?;
                        continue;
                    }
                };
                if !args.pinned {
                    if dependency.rename.is_some() {
                        args.verbose(|| {
                            shell_warn(&format!(
                                "ignoring {}, renamed dependencies are pinned",
                                dependency.toml_key(),
                            ))
                        })?;
                        pinned_present = true;
                        continue;
                    }

                    if let Ok(version_req) = VersionReq::parse(&old_version_req) {
                        if version_req.comparators.iter().any(|comparator| {
                            matches!(comparator.op, Op::Exact | Op::Less | Op::LessEq)
                        }) {
                            args.verbose(|| {
                                shell_warn(&format!(
                                    "ignoring {}, version ({}) is pinned",
                                    dependency.toml_key(),
                                    old_version_req
                                ))
                            })?;
                            pinned_present = true;
                            continue;
                        }
                    }
                }

                let new_version_req = if let Some(Some(new_version_req)) =
                    selected_dependencies.get(dependency.toml_key())
                {
                    new_version_req.to_owned()
                } else {
                    // Not checking `selected_dependencies.is_empty`, it was checked earlier
                    let new_version = if args.to_lockfile {
                        match find_locked_version(&dependency.name, &old_version_req, &locked) {
                            Some(new_version) => new_version,
                            None => {
                                args.verbose(|| {
                                    shell_warn(&format!(
                                        "ignoring {}, could not find package: not in lock file",
                                        dependency.toml_key(),
                                    ))
                                })?;
                                continue;
                            }
                        }
                    } else {
                        if dependency
                            .source
                            .as_ref()
                            .and_then(|s| s.as_registry())
                            .is_none()
                        {
                            args.verbose(|| {
                                let source = dependency
                                    .source()
                                    .map(|s| s.to_string())
                                    .unwrap_or_else(|| "unknown".to_owned());
                                shell_warn(&format!(
                                    "ignoring {}, source is {}",
                                    dependency.toml_key(),
                                    source
                                ))
                            })?;
                            continue;
                        }
                        // Update indices for any alternative registries, unless
                        // we're offline.
                        let registry_url = dependency
                            .registry()
                            .map(|registry| registry_url(&manifest_path, Some(registry)))
                            .transpose()?;
                        if !args.offline {
                            if let Some(registry_url) = &registry_url {
                                if updated_registries.insert(registry_url.to_owned()) {
                                    update_registry_index(registry_url, false)?;
                                }
                            }
                        }
                        let is_prerelease = old_version_req.contains('-');
                        let new_version = get_latest_dependency(
                            &dependency.name,
                            is_prerelease,
                            &manifest_path,
                            registry_url.as_ref(),
                        )
                        .map(|d| {
                            d.version()
                                .expect("registry packages always have a version")
                                .to_owned()
                        });
                        let new_version = match new_version {
                            Ok(new_version) => new_version,
                            Err(err) => {
                                args.verbose(|| {
                                    shell_warn(&format!(
                                        "ignoring {}, could not find package: {}",
                                        dependency.toml_key(),
                                        err
                                    ))
                                })?;
                                continue;
                            }
                        };
                        if old_version_compatible(&old_version_req, &new_version) {
                            args.verbose(|| {
                                shell_warn(&format!(
                                    "ignoring {}, version ({}) is compatible with {}",
                                    dependency.toml_key(),
                                    old_version_req,
                                    new_version
                                ))
                            })?;
                            compatible_present = true;
                            continue;
                        }
                        new_version
                    };
                    let mut new_version_req = new_version;
                    let new_ver: semver::Version = new_version_req.parse()?;
                    match cargo_edit::upgrade_requirement(&old_version_req, &new_ver) {
                        Ok(Some(version)) => {
                            new_version_req = version;
                        }
                        Err(_) => {}
                        _ => {
                            new_version_req = old_version_req.clone();
                        }
                    }
                    new_version_req
                };
                if new_version_req == old_version_req {
                    args.verbose(|| {
                        shell_warn(&format!(
                            "ignoring {}, version ({}) is unchanged",
                            dependency.toml_key(),
                            new_version_req
                        ))
                    })?;
                    continue;
                }
                print_upgrade(dependency.toml_key(), &old_version_req, &new_version_req)?;
                set_dep_version(dep_item, &new_version_req)?;
                crate_modified = true;
                any_crate_modified = true;
            }
        }
        if !args.dry_run && !args.locked && crate_modified {
            manifest.write()?;
        }
    }

    if args.locked && any_crate_modified {
        anyhow::bail!("cannot upgrade due to `--locked`");
    }

    let unused = selected_dependencies
        .keys()
        .filter(|k| !processed_keys.contains(k.as_str()))
        .map(|k| k.as_str())
        .collect::<Vec<_>>();
    match unused.len() {
        0 => {}
        1 => anyhow::bail!("dependency {} doesn't exist", unused.join(", ")),
        _ => anyhow::bail!("dependencies {} don't exist", unused.join(", ")),
    }

    if pinned_present {
        shell_note("Re-run with `--pinned` to upgrade pinned version requirements")?;
    }
    if compatible_present {
        shell_note("Re-run with `--to-lockfile` to upgrade compatible version requirements")?;
    }

    if args.dry_run {
        shell_warn("aborting upgrade due to dry run")?;
    }

    Ok(())
}

fn load_lockfile(targets: &[cargo_metadata::Package]) -> CargoResult<Vec<cargo_metadata::Package>> {
    // Get locked dependencies. For workspaces with multiple Cargo.toml
    // files, there is only a single lockfile, so it suffices to get
    // metadata for any one of Cargo.toml files.
    let package = targets
        .get(0)
        .ok_or_else(|| anyhow::format_err!("Invalid cargo config"))?;
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.manifest_path(package.manifest_path.clone());
    cmd.features(cargo_metadata::CargoOpt::AllFeatures);
    cmd.other_options(vec!["--locked".to_string()]);

    let result = cmd.exec()?;

    let locked = result
        .packages
        .into_iter()
        .filter(|p| p.source.is_some()) // Source is none for local packages
        .collect::<Vec<_>>();

    Ok(locked)
}

fn find_locked_version(
    dep_name: &str,
    old_version: &str,
    locked: &[cargo_metadata::Package],
) -> Option<String> {
    let req = semver::VersionReq::parse(old_version).ok()?;
    for p in locked {
        if dep_name == p.name && req.matches(&p.version) {
            return Some(p.version.to_string());
        }
    }
    None
}

fn old_version_compatible(old_version_req: &str, new_version: &str) -> bool {
    let old_version_req = match VersionReq::parse(old_version_req) {
        Ok(req) => req,
        Err(_) => return false,
    };

    let new_version = match semver::Version::parse(new_version) {
        Ok(new_version) => new_version,
        // HACK: Skip compatibility checks on incomplete version reqs
        Err(_) => return false,
    };

    old_version_req.matches(&new_version)
}

fn deprecated_message(message: &str) -> CargoResult<()> {
    let colorchoice = colorize_stderr();
    let mut output = StandardStream::stderr(colorchoice);
    output
        .set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))
        .with_context(|| "Failed to set output colour")?;
    writeln!(output, "{}", message).with_context(|| "Failed to write deprecated message")?;
    output
        .set_color(&ColorSpec::new())
        .with_context(|| "Failed to clear output colour")?;
    Ok(())
}

/// Print a message if the new dependency version is different from the old one.
fn print_upgrade(dep_name: &str, old_version: &str, new_version: &str) -> CargoResult<()> {
    let old_version = format_version_req(old_version);
    let new_version = format_version_req(new_version);

    shell_status(
        "Upgrading",
        &format!("{dep_name}: {old_version} -> {new_version}"),
    )?;

    Ok(())
}

fn format_version_req(version: &str) -> String {
    if version.chars().next().unwrap_or('0').is_ascii_digit() {
        format!("v{}", version)
    } else {
        version.to_owned()
    }
}
<commit_msg>fix(upgrade): Respect offline with lockfile loading<commit_after>use std::collections::BTreeSet;
use std::io::Write;
use std::path::PathBuf;

use cargo_edit::{
    colorize_stderr, find, get_latest_dependency, registry_url, resolve_manifests, set_dep_version,
    shell_note, shell_status, shell_warn, update_registry_index, CargoResult, Context, CrateSpec,
    Dependency, LocalManifest,
};
use clap::Args;
use indexmap::IndexMap;
use semver::{Op, VersionReq};
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};

/// Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).
#[derive(Debug, Args)]
#[clap(version)]
#[clap(after_help = "\
This command differs from `cargo update`, which updates the dependency versions recorded in the \
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version \
to upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io \
are supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--workspace` flag is supplied. The \
`--workspace` flag may be supplied in the presence of a virtual manifest.

If the '--to-lockfile' flag is supplied, all dependencies will be upgraded to the currently locked \
version as recorded in the Cargo.lock file. This flag requires that the Cargo.lock file is \
up-to-date. If the lock file is missing, or it needs to be updated, cargo-upgrade will exit with \
an error. If the '--to-lockfile' flag is supplied then the network won't be accessed.")]
pub struct UpgradeArgs {
    /// Crates to be upgraded.
    dependency: Vec<String>,

    /// Path to the manifest to upgrade
    #[clap(long, value_name = "PATH", parse(from_os_str))]
    manifest_path: Option<PathBuf>,

    /// Package id of the crate to add this dependency to.
    #[clap(
        long = "package",
        short = 'p',
        value_name = "PKGID",
        conflicts_with = "all",
        conflicts_with = "workspace"
    )]
    pkgid: Vec<String>,

    /// Upgrade all packages in the workspace.
    #[clap(
        long,
        help = "[deprecated in favor of `--workspace`]",
        conflicts_with = "workspace",
        conflicts_with = "pkgid"
    )]
    all: bool,

    /// Upgrade all packages in the workspace.
    #[clap(long, conflicts_with = "all", conflicts_with = "pkgid")]
    workspace: bool,

    /// Print changes to be made without making them.
    #[clap(long)]
    dry_run: bool,

    /// Upgrade dependencies pinned in the manifest.
    #[clap(long)]
    pinned: bool,

    /// Run without accessing the network
    #[clap(long)]
    offline: bool,

    /// Upgrade all packages to the version in the lockfile.
    #[clap(long, conflicts_with = "dependency")]
    to_lockfile: bool,

    /// Crates to exclude and not upgrade.
    #[clap(long)]
    exclude: Vec<String>,

    /// Require `Cargo.toml` to be up to date
    #[clap(long)]
    locked: bool,

    /// Use verbose output
    #[clap(short, long)]
    verbose: bool,

    /// Unstable (nightly-only) flags
    #[clap(short = 'Z', value_name = "FLAG", global = true, arg_enum)]
    unstable_features: Vec<UnstableOptions>,
}

impl UpgradeArgs {
    pub fn exec(self) -> CargoResult<()> {
        exec(self)
    }

    fn workspace(&self) -> bool {
        self.all || self.workspace
    }

    fn resolve_targets(&self) -> CargoResult<Vec<cargo_metadata::Package>> {
        resolve_manifests(
            self.manifest_path.as_deref(),
            self.workspace(),
            self.pkgid.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
        )
    }

    fn verbose<F>(&self, mut callback: F) -> CargoResult<()>
    where
        F: FnMut() -> CargoResult<()>,
    {
        if self.verbose {
            callback()
        } else {
            Ok(())
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
enum UnstableOptions {}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn exec(args: UpgradeArgs) -> CargoResult<()> {
    if args.all {
        deprecated_message("The flag `--all` has been deprecated in favor of `--workspace`")?;
    }

    if !args.offline && !args.to_lockfile {
        let url = registry_url(&find(args.manifest_path.as_deref())?, None)?;
        update_registry_index(&url, false)?;
    }

    let manifests = args.resolve_targets()?;
    let locked = args
        .to_lockfile
        .then(|| load_lockfile(&manifests, args.offline))
        .transpose()?
        .unwrap_or_default();

    let selected_dependencies = args
        .dependency
        .iter()
        .map(|name| {
            let spec = CrateSpec::resolve(name)?;
            Ok((spec.name, spec.version_req))
        })
        .collect::<CargoResult<IndexMap<_, _>>>()?;
    let mut processed_keys = BTreeSet::new();

    let mut updated_registries = BTreeSet::new();
    let mut any_crate_modified = false;
    let mut compatible_present = false;
    let mut pinned_present = false;
    for package in manifests {
        let mut manifest = LocalManifest::try_new(package.manifest_path.as_std_path())?;
        let mut crate_modified = false;
        let manifest_path = manifest.path.clone();
        shell_status("Checking", &format!("{}'s dependencies", package.name))?;
        for dep_table in manifest.get_dependency_tables_mut() {
            for (dep_key, dep_item) in dep_table.iter_mut() {
                let dep_key = dep_key.get();
                processed_keys.insert(dep_key.to_owned());
                if !selected_dependencies.is_empty() && !selected_dependencies.contains_key(dep_key)
                {
                    args.verbose(|| {
                        shell_warn(&format!("ignoring {}, excluded by user", dep_key))
                    })?;
                    continue;
                }
                if args.exclude.contains(&dep_key.to_owned()) {
                    args.verbose(|| {
                        shell_warn(&format!("ignoring {}, excluded by user", dep_key))
                    })?;
                    continue;
                }
                let dependency = match Dependency::from_toml(&manifest_path, dep_key, dep_item) {
                    Ok(dependency) => dependency,
                    Err(err) => {
                        shell_warn(&format!("ignoring {}, invalid entry: {}", dep_key, err))?;
                        continue;
                    }
                };
                let old_version_req = match dependency.version() {
                    Some(version_req) => version_req.to_owned(),
                    None => {
                        args.verbose(|| {
                            let source = dependency
                                .source()
                                .map(|s| s.to_string())
                                .unwrap_or_else(|| "unknown".to_owned());
                            shell_warn(&format!(
                                "ignoring {}, source is {}",
                                dependency.toml_key(),
                                source,
                            ))
                        })?;
                        continue;
                    }
                };
                if !args.pinned {
                    if dependency.rename.is_some() {
                        args.verbose(|| {
                            shell_warn(&format!(
                                "ignoring {}, renamed dependencies are pinned",
                                dependency.toml_key(),
                            ))
                        })?;
                        pinned_present = true;
                        continue;
                    }

                    if let Ok(version_req) = VersionReq::parse(&old_version_req) {
                        if version_req.comparators.iter().any(|comparator| {
                            matches!(comparator.op, Op::Exact | Op::Less | Op::LessEq)
                        }) {
                            args.verbose(|| {
                                shell_warn(&format!(
                                    "ignoring {}, version ({}) is pinned",
                                    dependency.toml_key(),
                                    old_version_req
                                ))
                            })?;
                            pinned_present = true;
                            continue;
                        }
                    }
                }

                let new_version_req = if let Some(Some(new_version_req)) =
                    selected_dependencies.get(dependency.toml_key())
                {
                    new_version_req.to_owned()
                } else {
                    // Not checking `selected_dependencies.is_empty`, it was checked earlier
                    let new_version = if args.to_lockfile {
                        match find_locked_version(&dependency.name, &old_version_req, &locked) {
                            Some(new_version) => new_version,
                            None => {
                                args.verbose(|| {
                                    shell_warn(&format!(
                                        "ignoring {}, could not find package: not in lock file",
                                        dependency.toml_key(),
                                    ))
                                })?;
                                continue;
                            }
                        }
                    } else {
                        if dependency
                            .source
                            .as_ref()
                            .and_then(|s| s.as_registry())
                            .is_none()
                        {
                            args.verbose(|| {
                                let source = dependency
                                    .source()
                                    .map(|s| s.to_string())
                                    .unwrap_or_else(|| "unknown".to_owned());
                                shell_warn(&format!(
                                    "ignoring {}, source is {}",
                                    dependency.toml_key(),
                                    source
                                ))
                            })?;
                            continue;
                        }
                        // Update indices for any alternative registries, unless
                        // we're offline.
                        let registry_url = dependency
                            .registry()
                            .map(|registry| registry_url(&manifest_path, Some(registry)))
                            .transpose()?;
                        if !args.offline {
                            if let Some(registry_url) = &registry_url {
                                if updated_registries.insert(registry_url.to_owned()) {
                                    update_registry_index(registry_url, false)?;
                                }
                            }
                        }
                        let is_prerelease = old_version_req.contains('-');
                        let new_version = get_latest_dependency(
                            &dependency.name,
                            is_prerelease,
                            &manifest_path,
                            registry_url.as_ref(),
                        )
                        .map(|d| {
                            d.version()
                                .expect("registry packages always have a version")
                                .to_owned()
                        });
                        let new_version = match new_version {
                            Ok(new_version) => new_version,
                            Err(err) => {
                                args.verbose(|| {
                                    shell_warn(&format!(
                                        "ignoring {}, could not find package: {}",
                                        dependency.toml_key(),
                                        err
                                    ))
                                })?;
                                continue;
                            }
                        };
                        if old_version_compatible(&old_version_req, &new_version) {
                            args.verbose(|| {
                                shell_warn(&format!(
                                    "ignoring {}, version ({}) is compatible with {}",
                                    dependency.toml_key(),
                                    old_version_req,
                                    new_version
                                ))
                            })?;
                            compatible_present = true;
                            continue;
                        }
                        new_version
                    };
                    let mut new_version_req = new_version;
                    let new_ver: semver::Version = new_version_req.parse()?;
                    match cargo_edit::upgrade_requirement(&old_version_req, &new_ver) {
                        Ok(Some(version)) => {
                            new_version_req = version;
                        }
                        Err(_) => {}
                        _ => {
                            new_version_req = old_version_req.clone();
                        }
                    }
                    new_version_req
                };
                if new_version_req == old_version_req {
                    args.verbose(|| {
                        shell_warn(&format!(
                            "ignoring {}, version ({}) is unchanged",
                            dependency.toml_key(),
                            new_version_req
                        ))
                    })?;
                    continue;
                }
                print_upgrade(dependency.toml_key(), &old_version_req, &new_version_req)?;
                set_dep_version(dep_item, &new_version_req)?;
                crate_modified = true;
                any_crate_modified = true;
            }
        }
        if !args.dry_run && !args.locked && crate_modified {
            manifest.write()?;
        }
    }

    if args.locked && any_crate_modified {
        anyhow::bail!("cannot upgrade due to `--locked`");
    }

    let unused = selected_dependencies
        .keys()
        .filter(|k| !processed_keys.contains(k.as_str()))
        .map(|k| k.as_str())
        .collect::<Vec<_>>();
    match unused.len() {
        0 => {}
        1 => anyhow::bail!("dependency {} doesn't exist", unused.join(", ")),
        _ => anyhow::bail!("dependencies {} don't exist", unused.join(", ")),
    }

    if pinned_present {
        shell_note("Re-run with `--pinned` to upgrade pinned version requirements")?;
    }
    if compatible_present {
        shell_note("Re-run with `--to-lockfile` to upgrade compatible version requirements")?;
    }

    if args.dry_run {
        shell_warn("aborting upgrade due to dry run")?;
    }

    Ok(())
}

fn load_lockfile(
    targets: &[cargo_metadata::Package],
    offline: bool,
) -> CargoResult<Vec<cargo_metadata::Package>> {
    // Get locked dependencies. For workspaces with multiple Cargo.toml
    // files, there is only a single lockfile, so it suffices to get
    // metadata for any one of Cargo.toml files.
    let package = targets
        .get(0)
        .ok_or_else(|| anyhow::format_err!("Invalid cargo config"))?;
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.manifest_path(package.manifest_path.clone());
    cmd.features(cargo_metadata::CargoOpt::AllFeatures);
    let mut other = vec!["--locked".to_owned()];
    if offline {
        other.push("--offline".to_owned());
    }
    cmd.other_options(other);

    let result = cmd.exec()?;

    let locked = result
        .packages
        .into_iter()
        .filter(|p| p.source.is_some()) // Source is none for local packages
        .collect::<Vec<_>>();

    Ok(locked)
}

fn find_locked_version(
    dep_name: &str,
    old_version: &str,
    locked: &[cargo_metadata::Package],
) -> Option<String> {
    let req = semver::VersionReq::parse(old_version).ok()?;
    for p in locked {
        if dep_name == p.name && req.matches(&p.version) {
            return Some(p.version.to_string());
        }
    }
    None
}

fn old_version_compatible(old_version_req: &str, new_version: &str) -> bool {
    let old_version_req = match VersionReq::parse(old_version_req) {
        Ok(req) => req,
        Err(_) => return false,
    };

    let new_version = match semver::Version::parse(new_version) {
        Ok(new_version) => new_version,
        // HACK: Skip compatibility checks on incomplete version reqs
        Err(_) => return false,
    };

    old_version_req.matches(&new_version)
}

fn deprecated_message(message: &str) -> CargoResult<()> {
    let colorchoice = colorize_stderr();
    let mut output = StandardStream::stderr(colorchoice);
    output
        .set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))
        .with_context(|| "Failed to set output colour")?;
    writeln!(output, "{}", message).with_context(|| "Failed to write deprecated message")?;
    output
        .set_color(&ColorSpec::new())
        .with_context(|| "Failed to clear output colour")?;
    Ok(())
}

/// Print a message if the new dependency version is different from the old one.
fn print_upgrade(dep_name: &str, old_version: &str, new_version: &str) -> CargoResult<()> {
    let old_version = format_version_req(old_version);
    let new_version = format_version_req(new_version);

    shell_status(
        "Upgrading",
        &format!("{dep_name}: {old_version} -> {new_version}"),
    )?;

    Ok(())
}

fn format_version_req(version: &str) -> String {
    if version.chars().next().unwrap_or('0').is_ascii_digit() {
        format!("v{}", version)
    } else {
        version.to_owned()
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::{Path, PathBuf};

use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;

/// Parse a dependency string used in Cargo.lock
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
    let split: Vec<&str> = dep_string.split_whitespace().collect();

    (split[0], split[1])
}

/// A reference to a package including it's name and the specific version.
pub(crate) struct PackageRef {
    pub name: String,
    pub version: String,
}

/// A collection of metadata for a library from cargo.
#[derive(Clone, Debug)]
pub(crate) struct Cargo {
    manifest_path: PathBuf,
    binding_crate_name: String,

    lock: Option<Lock>,
    metadata: Metadata,
}

impl Cargo {
    /// Gather metadata from cargo for a specific library and binding crate
    /// name. If dependency finding isn't needed then Cargo.lock files don't
    /// need to be parsed.
    pub(crate) fn load(crate_dir: &Path,
                       binding_crate_name: Option<&str>,
                       use_cargo_lock: bool) -> Result<Cargo, String> {
        let toml_path = crate_dir.join("Cargo.toml");
        let lock_path = crate_dir.join("Cargo.lock");

        let lock = if use_cargo_lock {
            Some(cargo_lock::lock(&lock_path)
                            .map_err(|x| format!("couldn't load {:?}: {:?}", lock_path, x))?)
        } else {
            None
        };
        let metadata = cargo_metadata::metadata(&toml_path)
                                      .map_err(|_| format!("couldn't execute `cargo metadata` with manifest {:?}.", toml_path))?;

        // Use the specified binding crate name or infer it from the manifest
        let manifest = cargo_toml::manifest(&toml_path)
                                  .map_err(|_| format!("couldn't load {:?}.", toml_path))?;

        let binding_crate_name = binding_crate_name.map_or(manifest.package.name.clone(),
                                                           |x| x.to_owned());

        Ok(Cargo {
            manifest_path: toml_path,
            binding_crate_name: binding_crate_name,
            lock: lock,
            metadata: metadata,
        })
    }

    pub(crate) fn binding_crate_name(&self) -> &str {
        &self.binding_crate_name
    }

    pub(crate) fn binding_crate_ref(&self) -> PackageRef {
        self.find_pkg_ref(&self.binding_crate_name).unwrap()
    }

    /// Finds the package reference in `cargo metadata` that has `package_name`
    /// ignoring the version.
    fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
        for package in &self.metadata.packages {
            if package.name == package_name {
                return Some(PackageRef {
                    name: package_name.to_owned(),
                    version: package.version.clone(),
                });
            }
        }
        None
    }

    /// Finds the package reference for a dependency of a crate using
    /// `Cargo.lock`.
    pub(crate) fn find_dep_ref(&self, package: &PackageRef, dependency_name: &str) -> Option<PackageRef> {
        if self.lock.is_none() {
            return None;
        }
        let lock = self.lock.as_ref().unwrap();

        // the name in Cargo.lock could use '-' instead of '_', so we need to
        // look for that too.
        let replaced_name = dependency_name.replace("_", "-");

        if let &Some(ref root) = &lock.root {
            if root.name == package.name && root.version == package.version {
                if let Some(ref deps) = root.dependencies {
                    for dep in deps {
                        let (name, version) = parse_dep_string(dep);

                        if name == dependency_name || name == &replaced_name {
                            return Some(PackageRef {
                                name: name.to_owned(),
                                version: version.to_owned(),
                            });
                        }
                    }
                }
                return None;
            }
        }

        if let &Some(ref lock_packages) = &lock.package {
            for lock_package in lock_packages {
                if lock_package.name == package.name && lock_package.version == package.version {
                    if let Some(ref deps) = lock_package.dependencies {
                        for dep in deps {
                            let (name, version) = parse_dep_string(dep);

                            if name == dependency_name || name == &replaced_name {
                                return Some(PackageRef {
                                    name: name.to_owned(),
                                    version: version.to_owned(),
                                });
                            }
                        }
                    }
                    return None;
                }
            }
        }
        None
    }

    /// Finds the directory for a specified package reference.
    #[allow(unused)]
    pub(crate) fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                return Path::new(&meta_package.manifest_path).parent()
                                                             .map(|x| x.to_owned());
            }
        }
        None
    }

    /// Finds `src/lib.rs` for a specified package reference.
    pub(crate) fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
        let kind_lib = String::from("lib");
        let kind_staticlib = String::from("staticlib");
        let kind_rlib = String::from("rlib");
        let kind_cdylib = String::from("cdylib");

        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                for target in &meta_package.targets {
                    if target.kind.contains(&kind_lib) ||
                       target.kind.contains(&kind_staticlib) ||
                       target.kind.contains(&kind_rlib) ||
                       target.kind.contains(&kind_cdylib) {
                        return Some(PathBuf::from(&target.src_path));
                    }
                }
                break;
            }
        }
        None
    }

    pub(crate) fn expand_crate(&self, package: &PackageRef) -> Result<String, String> {
        cargo_expand::expand(&self.manifest_path, &package.name, &package.version)
    }
}
<commit_msg>Don't error about missing lock file<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::{Path, PathBuf};

use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;

/// Parse a dependency string used in Cargo.lock
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
    let split: Vec<&str> = dep_string.split_whitespace().collect();

    (split[0], split[1])
}

/// A reference to a package including it's name and the specific version.
pub(crate) struct PackageRef {
    pub name: String,
    pub version: String,
}

/// A collection of metadata for a library from cargo.
#[derive(Clone, Debug)]
pub(crate) struct Cargo {
    manifest_path: PathBuf,
    binding_crate_name: String,

    lock: Option<Lock>,
    metadata: Metadata,
}

impl Cargo {
    /// Gather metadata from cargo for a specific library and binding crate
    /// name. If dependency finding isn't needed then Cargo.lock files don't
    /// need to be parsed.
    pub(crate) fn load(crate_dir: &Path,
                       binding_crate_name: Option<&str>,
                       use_cargo_lock: bool) -> Result<Cargo, String> {
        let toml_path = crate_dir.join("Cargo.toml");
        let lock_path = crate_dir.join("Cargo.lock");

        let lock = if use_cargo_lock {
            match cargo_lock::lock(&lock_path) {
                Ok(lock) => Some(lock),
                Err(x) => {
                    warn!("couldn't load lock file {:?}: {:?}", lock_path, x);
                    None
                }
            }
        } else {
            None
        };
        let metadata = cargo_metadata::metadata(&toml_path)
                                      .map_err(|_| format!("couldn't execute `cargo metadata` with manifest {:?}.", toml_path))?;

        // Use the specified binding crate name or infer it from the manifest
        let manifest = cargo_toml::manifest(&toml_path)
                                  .map_err(|_| format!("couldn't load {:?}.", toml_path))?;

        let binding_crate_name = binding_crate_name.map_or(manifest.package.name.clone(),
                                                           |x| x.to_owned());

        Ok(Cargo {
            manifest_path: toml_path,
            binding_crate_name: binding_crate_name,
            lock: lock,
            metadata: metadata,
        })
    }

    pub(crate) fn binding_crate_name(&self) -> &str {
        &self.binding_crate_name
    }

    pub(crate) fn binding_crate_ref(&self) -> PackageRef {
        self.find_pkg_ref(&self.binding_crate_name).unwrap()
    }

    /// Finds the package reference in `cargo metadata` that has `package_name`
    /// ignoring the version.
    fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
        for package in &self.metadata.packages {
            if package.name == package_name {
                return Some(PackageRef {
                    name: package_name.to_owned(),
                    version: package.version.clone(),
                });
            }
        }
        None
    }

    /// Finds the package reference for a dependency of a crate using
    /// `Cargo.lock`.
    pub(crate) fn find_dep_ref(&self, package: &PackageRef, dependency_name: &str) -> Option<PackageRef> {
        if self.lock.is_none() {
            return None;
        }
        let lock = self.lock.as_ref().unwrap();

        // the name in Cargo.lock could use '-' instead of '_', so we need to
        // look for that too.
        let replaced_name = dependency_name.replace("_", "-");

        if let &Some(ref root) = &lock.root {
            if root.name == package.name && root.version == package.version {
                if let Some(ref deps) = root.dependencies {
                    for dep in deps {
                        let (name, version) = parse_dep_string(dep);

                        if name == dependency_name || name == &replaced_name {
                            return Some(PackageRef {
                                name: name.to_owned(),
                                version: version.to_owned(),
                            });
                        }
                    }
                }
                return None;
            }
        }

        if let &Some(ref lock_packages) = &lock.package {
            for lock_package in lock_packages {
                if lock_package.name == package.name && lock_package.version == package.version {
                    if let Some(ref deps) = lock_package.dependencies {
                        for dep in deps {
                            let (name, version) = parse_dep_string(dep);

                            if name == dependency_name || name == &replaced_name {
                                return Some(PackageRef {
                                    name: name.to_owned(),
                                    version: version.to_owned(),
                                });
                            }
                        }
                    }
                    return None;
                }
            }
        }
        None
    }

    /// Finds the directory for a specified package reference.
    #[allow(unused)]
    pub(crate) fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                return Path::new(&meta_package.manifest_path).parent()
                                                             .map(|x| x.to_owned());
            }
        }
        None
    }

    /// Finds `src/lib.rs` for a specified package reference.
    pub(crate) fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
        let kind_lib = String::from("lib");
        let kind_staticlib = String::from("staticlib");
        let kind_rlib = String::from("rlib");
        let kind_cdylib = String::from("cdylib");

        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                for target in &meta_package.targets {
                    if target.kind.contains(&kind_lib) ||
                       target.kind.contains(&kind_staticlib) ||
                       target.kind.contains(&kind_rlib) ||
                       target.kind.contains(&kind_cdylib) {
                        return Some(PathBuf::from(&target.src_path));
                    }
                }
                break;
            }
        }
        None
    }

    pub(crate) fn expand_crate(&self, package: &PackageRef) -> Result<String, String> {
        cargo_expand::expand(&self.manifest_path, &package.name, &package.version)
    }
}
<|endoftext|>