<commit_before>extern crate postgres;
extern crate rustc_serialize;

use postgres::{Connection, SslMode};
use postgres::types::{ToSql};
use rustc_serialize::json::Json;

#[derive(Debug)]
struct TestRecord {
    id:   i32,
    name: String,
}

#[test]
fn sanity_test() {
    with_clean_database(|c| {
        let records = vec![
            TestRecord { id: 1, name: "Michael Baker".to_string() },
            TestRecord { id: 2, name: "Josh Cheek".to_string()   },
        ];

        for record in records.iter() {
            create_record(c, &record);
        }

        fetch_records(c);
    });
}

#[test]
fn basic_insert() {
    with_slot(|c| {
        let record = TestRecord { id: 1, name: "Michael Baker".to_string(), };
        create_record(c, &record);
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 1);
        let data = Json::from_str(&updates[0][..]).unwrap();
        let change = data.as_object().unwrap();
        let variant = change.get("variant").unwrap().as_string().unwrap();
        assert_eq!(variant, "Insert");
    });
}

#[test]
fn basic_delete() {
    with_slot(|c| {
        let record = TestRecord { id: 1, name: "Michael Baker".to_string() };
        create_record(c, &record);
        delete_record(c, 1);
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 2);
        let data = Json::from_str(&updates[1][..]).unwrap();
        let change = data.as_object().unwrap();
        let variant = change.get("variant").unwrap().as_string().unwrap();
        assert_eq!(variant, "Delete");
    });
}

#[test]
fn basic_update() {
    with_slot(|c| {
        let record = TestRecord { id: 1, name: "Michael Baker".to_string() };
        create_record(c, &record);
        update_record(c, TestRecord { id: 1, name: "Bichael Maker".to_string() });
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 2);
        let data = Json::from_str(&updates[1][..]).unwrap();
        let change = data.as_object().unwrap();
        let variant = change.get("variant").unwrap().as_string().unwrap();
        assert_eq!(variant, "Update");
    });
}

//
// [TODO] I want to move a lot of these into a utility module when I can figure out how to do that
//

fn execute(c: &Connection, command: &str, args: &[&ToSql]) {
    let stmt = c.prepare(command).unwrap();
    stmt.execute(args).unwrap();
}

fn execute_silent(c: &Connection, command: &str, args: &[&ToSql]) {
    let stmt = c.prepare(command).unwrap();
    match stmt.execute(args) { _ => {} };
}

fn fetch_updates(c: &Connection) -> Vec<String> {
    let stmt = c.prepare("SELECT * FROM pg_logical_slot_peek_changes('slot', NULL, NULL)").unwrap();
    let mut result = vec![];
    for r in stmt.query(&[]).unwrap() {
        result.push(r.get(2));
    }
    result
}

fn create_slot(c: &Connection) {
    execute(c, "select * from pg_create_logical_replication_slot('slot', 'thingy')", &[]);
}

fn drop_slot(c: &Connection) {
    execute_silent(c, "select pg_drop_replication_slot('slot')", &[]);
}

fn with_slot<F>(f: F) where F:Fn(&Connection) -> () {
    with_clean_database(|c| {
        drop_slot(c);
        create_slot(c);
        f(c);
        drop_slot(c);
    });
}

fn with_clean_database<F>(f: F) where F:Fn(&Connection) -> () {
    let c = connection();
    reset_database(&c);
    f(&c);
    drop_database(&c);
}

fn reset_database(c: &Connection) {
    drop_database(&c);
    create_database(&c);
}

fn create_database(c: &Connection) {
    execute(c, "create table test_table (id int primary key, name text)", &[]);
}

fn fetch_records(c: &Connection) -> Vec<TestRecord> {
    let stmt = c.prepare("select id, name from test_table").unwrap();
    let results = stmt.query(&[]).unwrap();
    results.iter().map(|r| {
        TestRecord {
            id:   r.get(0),
            name: r.get(1),
        }
    }).collect()
}

fn create_record(c: &Connection, r: &TestRecord) {
    execute(c, "insert into test_table (id, name) values ($1, $2)", &[
        &r.id,
        &r.name,
    ]);
}

fn delete_record(c: &Connection, id: i32) {
    execute(c, "delete from test_table where id = $1", &[&id]);
}

fn update_record(c: &Connection, new_record: TestRecord) {
    execute(c, "update test_table set name = $2 where id = $1", &[
        &new_record.id,
        &new_record.name
    ]);
}

fn drop_database(c: &Connection) {
    execute(c, "drop table if exists test_table", &[]);
}

fn connection_string() -> String {
    match std::env::var("POSTGRES_URL") {
        Ok(val) => val,
        Err(e)  => panic!(format!("You must set the POSTGRES_URL environment variable to point to a running Postgres test database when running automated tests: {}", e)),
    }
}

fn connection() -> Connection {
    match Connection::connect(&connection_string()[..], &SslMode::None) {
        Ok(c)  => c,
        Err(e) => panic!(format!("Could not connect to the test database: {}", e)),
    }
}
<commit_msg>Cleans up a Row -> Vec conversion<commit_after>extern crate postgres;
extern crate rustc_serialize;

use postgres::{Connection, SslMode};
use postgres::types::{ToSql};
use rustc_serialize::json::Json;

#[derive(Debug)]
struct TestRecord {
    id:   i32,
    name: String,
}

#[test]
fn sanity_test() {
    with_clean_database(|c| {
        let records = vec![
            TestRecord { id: 1, name: "Michael Baker".to_string() },
            TestRecord { id: 2, name: "Josh Cheek".to_string()   },
        ];

        for record in records.iter() {
            create_record(c, &record);
        }

        fetch_records(c);
    });
}

#[test]
fn basic_insert() {
    with_slot(|c| {
        let record = TestRecord { id: 1, name: "Michael Baker".to_string(), };
        create_record(c, &record);
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 1);
        let data = Json::from_str(&updates[0][..]).unwrap();
        let change = data.as_object().unwrap();
        let variant = change.get("variant").unwrap().as_string().unwrap();
        assert_eq!(variant, "Insert");
    });
}

#[test]
fn basic_delete() {
    with_slot(|c| {
        let record = TestRecord { id: 1, name: "Michael Baker".to_string() };
        create_record(c, &record);
        delete_record(c, 1);
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 2);
        let data = Json::from_str(&updates[1][..]).unwrap();
        let change = data.as_object().unwrap();
        let variant = change.get("variant").unwrap().as_string().unwrap();
        assert_eq!(variant, "Delete");
    });
}

#[test]
fn basic_update() {
    with_slot(|c| {
        let record = TestRecord { id: 1, name: "Michael Baker".to_string() };
        create_record(c, &record);
        update_record(c, TestRecord { id: 1, name: "Bichael Maker".to_string() });
        let updates = fetch_updates(c);
        assert_eq!(updates.len(), 2);
        let data = Json::from_str(&updates[1][..]).unwrap();
        let change = data.as_object().unwrap();
        let variant = change.get("variant").unwrap().as_string().unwrap();
        assert_eq!(variant, "Update");
    });
}

//
// [TODO] I want to move a lot of these into a utility module when I can figure out how to do that
//

fn execute(c: &Connection, command: &str, args: &[&ToSql]) {
    let stmt = c.prepare(command).unwrap();
    stmt.execute(args).unwrap();
}

fn execute_silent(c: &Connection, command: &str, args: &[&ToSql]) {
    let stmt = c.prepare(command).unwrap();
    match stmt.execute(args) { _ => {} };
}

fn fetch_updates(c: &Connection) -> Vec<String> {
    let stmt = c.prepare("SELECT * FROM pg_logical_slot_peek_changes('slot', NULL, NULL)").unwrap();
    stmt.query(&[]).unwrap().iter().map(|r| { r.get(2) }).collect()
}

fn create_slot(c: &Connection) {
    execute(c, "select * from pg_create_logical_replication_slot('slot', 'thingy')", &[]);
}

fn drop_slot(c: &Connection) {
    execute_silent(c, "select pg_drop_replication_slot('slot')", &[]);
}

fn with_slot<F>(f: F) where F:Fn(&Connection) -> () {
    with_clean_database(|c| {
        drop_slot(c);
        create_slot(c);
        f(c);
        drop_slot(c);
    });
}

fn with_clean_database<F>(f: F) where F:Fn(&Connection) -> () {
    let c = connection();
    reset_database(&c);
    f(&c);
    drop_database(&c);
}

fn reset_database(c: &Connection) {
    drop_database(&c);
    create_database(&c);
}

fn create_database(c: &Connection) {
    execute(c, "create table test_table (id int primary key, name text)", &[]);
}

fn fetch_records(c: &Connection) -> Vec<TestRecord> {
    let stmt = c.prepare("select id, name from test_table").unwrap();
    let results = stmt.query(&[]).unwrap();
    results.iter().map(|r| {
        TestRecord {
            id:   r.get(0),
            name: r.get(1),
        }
    }).collect()
}

fn create_record(c: &Connection, r: &TestRecord) {
    execute(c, "insert into test_table (id, name) values ($1, $2)", &[
        &r.id,
        &r.name,
    ]);
}

fn delete_record(c: &Connection, id: i32) {
    execute(c, "delete from test_table where id = $1", &[&id]);
}

fn update_record(c: &Connection, new_record: TestRecord) {
    execute(c, "update test_table set name = $2 where id = $1", &[
        &new_record.id,
        &new_record.name
    ]);
}

fn drop_database(c: &Connection) {
    execute(c, "drop table if exists test_table", &[]);
}

fn connection_string() -> String {
    match std::env::var("POSTGRES_URL") {
        Ok(val) => val,
        Err(e)  => panic!(format!("You must set the POSTGRES_URL environment variable to point to a running Postgres test database when running automated tests: {}", e)),
    }
}

fn connection() -> Connection {
    match Connection::connect(&connection_string()[..], &SslMode::None) {
        Ok(c)  => c,
        Err(e) => panic!(format!("Could not connect to the test database: {}", e)),
    }
}
<|endoftext|>


<commit_before>extern crate lrs;

#[cfg(test)]
mod tests {
    use lrs::atom::*;
    use lrs::token::*;
    use lrs::token::Operator::*;

    // #[test]
    fn test_operator() {
        let result = parse_Op("+");
        assert_eq!(result, Ok(Atom::from(Add)));

        let result = parse_Op("-");
        assert_eq!(result, Ok(Atom::from(Sub)));

        let result = parse_Op("*");
        assert_eq!(result, Ok(Atom::from(Mul)));

        let result = parse_Op("/");
        assert_eq!(result, Ok(Atom::from(Div)));
    }

    // #[test]
    // fn test_numeric() {
    //     let result = parser(numeric).parse("1000");
    //     assert_eq!(result, Ok((Expr::from(1000), "")));
    // }
    //
    // #[test]
    // fn test_symbol() {
    //     let result = parser(symbol).parse("+1");
    //     assert_eq!(result, Ok((Expr::Atom(Atom::Sym(Add)), "1")));
    // }
    //
    // #[test]
    // fn test_expr() {
    //     let result = parser(expr).parse("( 1 2 3 )");
    //     let expr = Expr::from(vec![1, 2, 3]);
    //     assert_eq!(result, Ok((expr, "")));
    // }
}
<commit_msg>Comment out all tests<commit_after>// extern crate lrs;
//
// #[cfg(test)]
// mod tests {
//     use lrs::atom::*;
//     use lrs::token::*;
//     use lrs::token::Operator::*;
//
//     // #[test]
//     fn test_operator() {
//         let result = parse_Op("+");
//         assert_eq!(result, Ok(Atom::from(Add)));
//
//         let result = parse_Op("-");
//         assert_eq!(result, Ok(Atom::from(Sub)));
//
//         let result = parse_Op("*");
//         assert_eq!(result, Ok(Atom::from(Mul)));
//
//         let result = parse_Op("/");
//         assert_eq!(result, Ok(Atom::from(Div)));
//     }
//
//     // #[test]
//     // fn test_numeric() {
//     //     let result = parser(numeric).parse("1000");
//     //     assert_eq!(result, Ok((Expr::from(1000), "")));
//     // }
//     //
//     // #[test]
//     // fn test_symbol() {
//     //     let result = parser(symbol).parse("+1");
//     //     assert_eq!(result, Ok((Expr::Atom(Atom::Sym(Add)), "1")));
//     // }
//     //
//     // #[test]
//     // fn test_expr() {
//     //     let result = parser(expr).parse("( 1 2 3 )");
//     //     let expr = Expr::from(vec![1, 2, 3]);
//     //     assert_eq!(result, Ok((expr, "")));
//     // }
// }
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    dead_code,
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
#[macro_use] extern crate itertools;
#[cfg(unix)] extern crate xdg_basedir;
extern crate env_logger;
extern crate tempfile;
extern crate ansi_term;

extern crate clap;
extern crate toml;

extern crate libimagstore;
extern crate libimagstorestdhook;
extern crate libimagutil;
#[macro_use] extern crate libimagerror;

mod configuration;

pub mod error;
pub mod logger;
pub mod runtime;
pub mod setup;

<commit_msg>Make configuration module public<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    dead_code,
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
#[macro_use] extern crate itertools;
#[cfg(unix)] extern crate xdg_basedir;
extern crate env_logger;
extern crate tempfile;
extern crate ansi_term;

extern crate clap;
extern crate toml;

extern crate libimagstore;
extern crate libimagstorestdhook;
extern crate libimagutil;
#[macro_use] extern crate libimagerror;

pub mod error;
pub mod configuration;
pub mod logger;
pub mod runtime;
pub mod setup;

<|endoftext|>


<commit_before>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate approx;

extern crate cgmath;
extern crate collision;

use cgmath::{Point3, Vector3};
use cgmath::{ApproxEq};
use collision::{Bound, Relation, Plane};

#[test]
fn test_homogeneous() {
    let p = Point3::new(1.0f64, 2.0f64, 3.0f64);
    assert_ulps_eq!(p, &Point3::from_homogeneous(p.to_homogeneous()));
}

#[test]
fn test_bound() {
    let point = Point3::new(1f32, 2.0, 3.0);
    let normal = Vector3::new(0f32, -0.8, -0.36);
    let plane = Plane::from_point_normal(point, normal);

    assert_eq!(point.relate_plane(plane), Relation::Cross);
    assert_eq!((point + normal).relate_plane(plane), Relation::In);
    assert_eq!((point + normal * -1.0).relate_plane(plane), Relation::Out);
}
<commit_msg>Remove: unneeded use statement<commit_after>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate approx;

extern crate cgmath;
extern crate collision;

use cgmath::{Point3, Vector3};
use collision::{Bound, Relation, Plane};

#[test]
fn test_homogeneous() {
    let p = Point3::new(1.0f64, 2.0f64, 3.0f64);
    assert_ulps_eq!(p, &Point3::from_homogeneous(p.to_homogeneous()));
}

#[test]
fn test_bound() {
    let point = Point3::new(1f32, 2.0, 3.0);
    let normal = Vector3::new(0f32, -0.8, -0.36);
    let plane = Plane::from_point_normal(point, normal);

    assert_eq!(point.relate_plane(plane), Relation::Cross);
    assert_eq!((point + normal).relate_plane(plane), Relation::In);
    assert_eq!((point + normal * -1.0).relate_plane(plane), Relation::Out);
}
<|endoftext|>


<commit_before>//
use clap::{crate_version};

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

use clap::{App, ArgMatches, SubCommand, AppSettings};

use mdbook_1::{MDBook as MDBook1};
use mdbook_1::errors::{Result as Result1};

use mdbook_2::{MDBook as MDBook2};
use mdbook_2::errors::{Result as Result2};

fn main() {
    let d_message = "-d, --dest-dir=[dest-dir]
'The output directory for your book{n}(Defaults to ./book when omitted)'";
    let dir_message = "[dir]
'A directory for your book{n}(Defaults to Current Directory when omitted)'";
    let vers_message = "-m, --mdbook-vers=[md-version]
'The version of mdbook to use for your book{n}(Defaults to 1 when omitted)'";

    let matches = App::new("rustbook")
                    .about("Build a book with mdBook")
                    .author("Steve Klabnik <steve@steveklabnik.com>")
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage(d_message)
                        .arg_from_usage(dir_message)
                        .arg_from_usage(vers_message))
                    .get_matches();

    // Check which subcomamnd the user ran...
    match matches.subcommand() {
        ("build", Some(sub_matches)) => {
            match sub_matches.value_of("mdbook-vers") {
                None | Some("1") => {
                    if let Err(e) = build_1(sub_matches) {
                        eprintln!("Error: {}", e);

                        for cause in e.iter().skip(1) {
                            eprintln!("\tCaused By: {}", cause);
                        }

                        ::std::process::exit(101);
                    }
                }
                Some("2") => {
                    if let Err(e) = build_2(sub_matches) {
                        eprintln!("Error: {}", e);

                        for cause in e.iter().skip(1) {
                            eprintln!("\tCaused By: {}", cause);
                        }

                        ::std::process::exit(101);
                    }
                }
                _ => {
                    panic!("Invalid mdBook version! Select '1' or '2'");
                }
            };
        },
        (_, _) => unreachable!(),
    };
}

// Build command implementation
pub fn build_1(args: &ArgMatches) -> Result1<()> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook1::load(&book_dir)?;

    // Set this to allow us to catch bugs in advance.
    book.config.build.create_missing = false;

    if let Some(dest_dir) = args.value_of("dest-dir") {
        book.config.build.build_dir = PathBuf::from(dest_dir);
    }

    book.build()?;

    Ok(())
}

// Build command implementation
pub fn build_2(args: &ArgMatches) -> Result2<()> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook2::load(&book_dir)?;

    // Set this to allow us to catch bugs in advance.
    book.config.build.create_missing = false;

    if let Some(dest_dir) = args.value_of("dest-dir") {
        book.config.build.build_dir = PathBuf::from(dest_dir);
    }

    book.build()?;

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}
<commit_msg>Rollup merge of #58833 - Centril:rust_2018_idioms-rustbook, r=oli-obk<commit_after>#![deny(rust_2018_idioms)]

use clap::{crate_version};

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

use clap::{App, ArgMatches, SubCommand, AppSettings};

use mdbook_1::{MDBook as MDBook1};
use mdbook_1::errors::{Result as Result1};

use mdbook_2::{MDBook as MDBook2};
use mdbook_2::errors::{Result as Result2};

fn main() {
    let d_message = "-d, --dest-dir=[dest-dir]
'The output directory for your book{n}(Defaults to ./book when omitted)'";
    let dir_message = "[dir]
'A directory for your book{n}(Defaults to Current Directory when omitted)'";
    let vers_message = "-m, --mdbook-vers=[md-version]
'The version of mdbook to use for your book{n}(Defaults to 1 when omitted)'";

    let matches = App::new("rustbook")
                    .about("Build a book with mdBook")
                    .author("Steve Klabnik <steve@steveklabnik.com>")
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage(d_message)
                        .arg_from_usage(dir_message)
                        .arg_from_usage(vers_message))
                    .get_matches();

    // Check which subcomamnd the user ran...
    match matches.subcommand() {
        ("build", Some(sub_matches)) => {
            match sub_matches.value_of("mdbook-vers") {
                None | Some("1") => {
                    if let Err(e) = build_1(sub_matches) {
                        eprintln!("Error: {}", e);

                        for cause in e.iter().skip(1) {
                            eprintln!("\tCaused By: {}", cause);
                        }

                        ::std::process::exit(101);
                    }
                }
                Some("2") => {
                    if let Err(e) = build_2(sub_matches) {
                        eprintln!("Error: {}", e);

                        for cause in e.iter().skip(1) {
                            eprintln!("\tCaused By: {}", cause);
                        }

                        ::std::process::exit(101);
                    }
                }
                _ => {
                    panic!("Invalid mdBook version! Select '1' or '2'");
                }
            };
        },
        (_, _) => unreachable!(),
    };
}

// Build command implementation
pub fn build_1(args: &ArgMatches<'_>) -> Result1<()> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook1::load(&book_dir)?;

    // Set this to allow us to catch bugs in advance.
    book.config.build.create_missing = false;

    if let Some(dest_dir) = args.value_of("dest-dir") {
        book.config.build.build_dir = PathBuf::from(dest_dir);
    }

    book.build()?;

    Ok(())
}

// Build command implementation
pub fn build_2(args: &ArgMatches<'_>) -> Result2<()> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook2::load(&book_dir)?;

    // Set this to allow us to catch bugs in advance.
    book.config.build.create_missing = false;

    if let Some(dest_dir) = args.value_of("dest-dir") {
        book.config.build.build_dir = PathBuf::from(dest_dir);
    }

    book.build()?;

    Ok(())
}

fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait Trait<'a> {}

fn main() {
    let _: &for<'a> Trait<'a> + 'static;
    //~^ ERROR expected a path on the left-hand side of `+`, not `& for<'a>Trait<'a>`
    //~| NOTE expected a path
    //~| HELP try adding parentheses
    //~| SUGGESTION &( for<'a>Trait<'a> + 'static)
}
<commit_msg>Fix a parse-fail test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait Trait<'a> {}

fn main() {
    let _: &for<'a> Trait<'a> + 'static;
    //~^ ERROR expected a path on the left-hand side of `+`, not `& for<'a>Trait<'a>`
    //~| HELP try adding parentheses
    //~| SUGGESTION &( for<'a>Trait<'a> + 'static)
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;

use arch::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, Context, ContextMemory};
use arch::elf::Elf;
use arch::memory;
use arch::regs::Regs;

use collections::string::{String, ToString};
use collections::vec::Vec;

use common::slice::GetSlice;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use fs::Url;

use system::error::{Error, Result, ENOEXEC};

fn execute_inner(url: Url) -> Result<(*mut Context, usize)> {
    let mut vec: Vec<u8> = Vec::new();

    {
        let mut resource = try!(url.open());
        'reading: loop {
            let mut bytes = [0; 4096];
            match resource.read(&mut bytes) {
                Ok(0) => break 'reading,
                Ok(count) => vec.push_all(bytes.get_slice(.. count)),
                Err(err) => return Err(err)
            }
        }
    }

    match Elf::from(&vec) {
        Ok(executable) => {
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    let offset = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + offset);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy((physical_address + offset) as *mut u8,
                                 (executable.data.as_ptr() as usize + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            ::memset((physical_address + offset + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - offset,
                            virtual_size: virtual_size + offset,
                            writeable: segment.flags & 2 == 2,
                            allocated: true,
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                let mut contexts = ::env().contexts.lock();
                let mut context = try!(contexts.current_mut());
                context.name = url.string;
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));

                unsafe { context.unmap() };
                context.memory = Arc::new(UnsafeCell::new(memory));
                unsafe { context.map() };

                Ok((context.deref_mut(), entry))
            } else {
                Err(Error::new(ENOEXEC))
            }
        },
        Err(msg) => {
            debugln!("execute: failed to exec '{}': {}", url.string, msg);
            Err(Error::new(ENOEXEC))
        }
    }
}

pub fn execute_outer(context_ptr: *mut Context, entry: usize, mut args: Vec<String>) -> ! {
    Context::spawn("kexec".to_string(), box move || {
        let context = unsafe { &mut *context_ptr };

        let mut context_args: Vec<usize> = Vec::new();
        context_args.push(0); // ENVP
        context_args.push(0); // ARGV NULL
        let mut argc = 0;
        for i in 0..args.len() {
            let reverse_i = args.len() - i - 1;
            if let Some(ref mut arg) = args.get_mut(reverse_i) {
                if ! arg.ends_with('\0') {
                    arg.push('\0');
                }

                let physical_address = arg.as_ptr() as usize;
                let virtual_address = context.next_mem();
                let virtual_size = arg.len();

                mem::forget(arg);

                unsafe {
                    (*context.memory.get()).push(ContextMemory {
                        physical_address: physical_address,
                        virtual_address: virtual_address,
                        virtual_size: virtual_size,
                        writeable: false,
                        allocated: true,
                    });
                }

                context_args.push(virtual_address as usize);
                argc += 1;
            }
        }
        context_args.push(argc);

        context.regs = Regs::default();
        context.regs.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

        context.stack = Some(ContextMemory {
            physical_address: unsafe { memory::alloc(CONTEXT_STACK_SIZE) },
            virtual_address: CONTEXT_STACK_ADDR,
            virtual_size: CONTEXT_STACK_SIZE,
            writeable: true,
            allocated: true,
        });

        let user_sp = if let Some(ref stack) = context.stack {
            let mut sp = stack.physical_address + stack.virtual_size - 128;
            for arg in context_args.iter() {
                sp -= mem::size_of::<usize>();
                unsafe { ptr::write(sp as *mut usize, *arg) };
            }
            sp - stack.physical_address + stack.virtual_address
        } else {
            0
        };

        unsafe {
            context.push(0x20 | 3);
            context.push(user_sp);
            context.push(1 << 9);
            context.push(0x18 | 3);
            context.push(entry);
            context.push(context_userspace as usize);
        }
    });

    loop {
        unsafe { context_switch(false) };
    }
}

/// Execute an executable
pub fn execute(args: Vec<String>) -> Result<usize> {
    let contexts = ::env().contexts.lock();
    let current = try!(contexts.current());

    if let Ok((context_ptr, entry)) = execute_inner(Url::from_string(current.canonicalize(args.get(0).map_or("", |p| &p)))) {
        execute_outer(context_ptr, entry, args);
    }else{
        let (context_ptr, entry) = try!(execute_inner(Url::from_string("file:/bin/".to_string() + args.get(0).map_or("", |p| &p))));
        execute_outer(context_ptr, entry, args);
    }
}
<commit_msg>Fix arguments<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;

use arch::context::{CONTEXT_STACK_SIZE, CONTEXT_STACK_ADDR, context_switch, context_userspace, Context, ContextMemory};
use arch::elf::Elf;
use arch::memory;
use arch::regs::Regs;

use collections::string::{String, ToString};
use collections::vec::Vec;

use common::slice::GetSlice;

use core::cell::UnsafeCell;
use core::ops::DerefMut;
use core::{mem, ptr};

use fs::Url;

use system::error::{Error, Result, ENOEXEC};

fn execute_inner(url: Url) -> Result<(*mut Context, usize)> {
    let mut vec: Vec<u8> = Vec::new();

    {
        let mut resource = try!(url.open());
        'reading: loop {
            let mut bytes = [0; 4096];
            match resource.read(&mut bytes) {
                Ok(0) => break 'reading,
                Ok(count) => vec.push_all(bytes.get_slice(.. count)),
                Err(err) => return Err(err)
            }
        }
    }

    match Elf::from(&vec) {
        Ok(executable) => {
            let entry = unsafe { executable.entry() };
            let mut memory = Vec::new();
            unsafe {
                for segment in executable.load_segment().iter() {
                    let virtual_address = segment.vaddr as usize;
                    let virtual_size = segment.mem_len as usize;

                    let offset = virtual_address % 4096;

                    let physical_address = memory::alloc(virtual_size + offset);

                    if physical_address > 0 {
                        // Copy progbits
                        ::memcpy((physical_address + offset) as *mut u8,
                                 (executable.data.as_ptr() as usize + segment.off as usize) as *const u8,
                                 segment.file_len as usize);
                        // Zero bss
                        if segment.mem_len > segment.file_len {
                            ::memset((physical_address + offset + segment.file_len as usize) as *mut u8,
                                    0,
                                    segment.mem_len as usize - segment.file_len as usize);
                        }

                        memory.push(ContextMemory {
                            physical_address: physical_address,
                            virtual_address: virtual_address - offset,
                            virtual_size: virtual_size + offset,
                            writeable: segment.flags & 2 == 2,
                            allocated: true,
                        });
                    }
                }
            }

            if entry > 0 && ! memory.is_empty() {
                let mut contexts = ::env().contexts.lock();
                let mut context = try!(contexts.current_mut());
                context.name = url.string;
                context.cwd = Arc::new(UnsafeCell::new(unsafe { (*context.cwd.get()).clone() }));

                unsafe { context.unmap() };
                context.memory = Arc::new(UnsafeCell::new(memory));
                unsafe { context.map() };

                Ok((context.deref_mut(), entry))
            } else {
                Err(Error::new(ENOEXEC))
            }
        },
        Err(msg) => {
            debugln!("execute: failed to exec '{}': {}", url.string, msg);
            Err(Error::new(ENOEXEC))
        }
    }
}

pub fn execute_outer(context_ptr: *mut Context, entry: usize, mut args: Vec<String>) -> ! {
    Context::spawn("kexec".to_string(), box move || {
        let context = unsafe { &mut *context_ptr };

        let mut context_args: Vec<usize> = Vec::new();
        context_args.push(0); // ENVP
        context_args.push(0); // ARGV NULL
        let mut argc = 0;
        while let Some(mut arg) = args.pop() {
            if ! arg.ends_with('\0') {
                arg.push('\0');
            }

            let virtual_address = context.next_mem();

            unsafe {
                let arg_ptr = Box::into_raw(arg.into_boxed_str());

                (*context.memory.get()).push(ContextMemory {
                    physical_address: (*arg_ptr).as_ptr() as usize,
                    virtual_address: virtual_address,
                    virtual_size: (*arg_ptr).len(),
                    writeable: false,
                    allocated: true,
                });
            }

            context_args.push(virtual_address as usize);
            argc += 1;
        }
        context_args.push(argc);

        context.regs = Regs::default();
        context.regs.sp = context.kernel_stack + CONTEXT_STACK_SIZE - 128;

        context.stack = Some(ContextMemory {
            physical_address: unsafe { memory::alloc(CONTEXT_STACK_SIZE) },
            virtual_address: CONTEXT_STACK_ADDR,
            virtual_size: CONTEXT_STACK_SIZE,
            writeable: true,
            allocated: true,
        });

        let user_sp = if let Some(ref stack) = context.stack {
            let mut sp = stack.physical_address + stack.virtual_size - 128;
            for arg in context_args.iter() {
                sp -= mem::size_of::<usize>();
                unsafe { ptr::write(sp as *mut usize, *arg) };
            }
            sp - stack.physical_address + stack.virtual_address
        } else {
            0
        };

        unsafe {
            context.push(0x20 | 3);
            context.push(user_sp);
            context.push(1 << 9);
            context.push(0x18 | 3);
            context.push(entry);
            context.push(context_userspace as usize);
        }
    });

    loop {
        unsafe { context_switch(false) };
    }
}

/// Execute an executable
pub fn execute(args: Vec<String>) -> Result<usize> {
    let contexts = ::env().contexts.lock();
    let current = try!(contexts.current());

    if let Ok((context_ptr, entry)) = execute_inner(Url::from_string(current.canonicalize(args.get(0).map_or("", |p| &p)))) {
        execute_outer(context_ptr, entry, args);
    }else{
        let (context_ptr, entry) = try!(execute_inner(Url::from_string("file:/bin/".to_string() + args.get(0).map_or("", |p| &p))));
        execute_outer(context_ptr, entry, args);
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_impl_items;
use ra_syntax::{
    ast::{self, edit},
    AstNode, SyntaxKind, SyntaxNode, TextRange,
};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    let trigger = ctx.token.ancestors().find(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => true,
        _ => false,
    });

    let impl_block = trigger
        .as_ref()
        .and_then(|node| node.parent())
        .and_then(|node| node.parent())
        .and_then(|node| ast::ImplBlock::cast(node));

    if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
        match trigger.kind() {
            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: &hir::Function,
) {
    let display = FunctionSignature::from_hir(ctx.db, func.clone());

    let fn_name = func.name(ctx.db).to_string();

    let label = if func.params(ctx.db).len() > 0 {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone())
        .lookup_by(fn_name)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());

    builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

    let snippet = format!("type {} = ", alias_name);

    let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: &hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range =
            TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::strip_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ)
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 142),
                delete: [138; 142),
                insert: "fn foo() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: [200; 201),
                delete: [197; 201),
                insert: "fn foo_bar() {}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

    #[test]
    fn completes_only_on_top_level() {
        let completions = complete(
            r"
            trait Test {
                fn foo();

                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {
                    <|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [144; 145),
                delete: [141; 145),
                insert: "fn foo<T>() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [166; 167),
                delete: [163; 167),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [124; 125),
                delete: [119; 125),
                insert: "type SomeType = ",
                kind: TypeAlias,
                lookup: "SomeType",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [133; 134),
                delete: [127; 134),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [138; 139),
                delete: [132; 139),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<commit_msg>Added module doc comment to explain the purpose of the completion.<commit_after>//! Completion for associated items in a trait implementation.
//!
//! This module adds the completion items related to implementing associated
//! items within a `impl Trait for Struct` block. The current context node
//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node
//! and an direct child of an `IMPL_BLOCK`.
//!
//! # Examples
//!
//! Considering the following trait `impl`:
//!
//! ```ignore
//! trait SomeTrait {
//!     fn foo();
//! }
//!
//! impl SomeTrait for () {
//!     fn f<|>
//! }
//! ```
//!
//! may result in the completion of the following method:
//!
//! ```ignore
//! # trait SomeTrait {
//! #    fn foo();
//! # }
//!
//! impl SomeTrait for () {
//!     fn foo() {}<|>
//! }
//! ```

use hir::{self, Docs, HasSource};
use ra_assists::utils::get_missing_impl_items;
use ra_syntax::{
    ast::{self, edit},
    AstNode, SyntaxKind, SyntaxNode, TextRange,
};
use ra_text_edit::TextEdit;

use crate::{
    completion::{
        CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
    },
    display::FunctionSignature,
};

pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
    let trigger = ctx.token.ancestors().find(|p| match p.kind() {
        SyntaxKind::FN_DEF
        | SyntaxKind::TYPE_ALIAS_DEF
        | SyntaxKind::CONST_DEF
        | SyntaxKind::BLOCK_EXPR => true,
        _ => false,
    });

    let impl_block = trigger
        .as_ref()
        .and_then(|node| node.parent())
        .and_then(|node| node.parent())
        .and_then(|node| ast::ImplBlock::cast(node));

    if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
        match trigger.kind() {
            SyntaxKind::FN_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Function(fn_item) => Some(fn_item),
                        _ => None,
                    })
                {
                    add_function_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::TYPE_ALIAS_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::TypeAlias(type_item) => Some(type_item),
                        _ => None,
                    })
                {
                    add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            SyntaxKind::CONST_DEF => {
                for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block)
                    .iter()
                    .filter_map(|item| match item {
                        hir::AssocItem::Const(const_item) => Some(const_item),
                        _ => None,
                    })
                {
                    add_const_impl(&trigger, acc, ctx, &missing_fn);
                }
            }

            _ => {}
        }
    }
}

fn add_function_impl(
    fn_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    func: &hir::Function,
) {
    let display = FunctionSignature::from_hir(ctx.db, func.clone());

    let fn_name = func.name(ctx.db).to_string();

    let label = if func.params(ctx.db).len() > 0 {
        format!("fn {}(..)", fn_name)
    } else {
        format!("fn {}()", fn_name)
    };

    let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone())
        .lookup_by(fn_name)
        .set_documentation(func.docs(ctx.db));

    let completion_kind = if func.has_self_param(ctx.db) {
        CompletionItemKind::Method
    } else {
        CompletionItemKind::Function
    };

    let snippet = format!("{} {{}}", display);

    let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end());

    builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc);
}

fn add_type_alias_impl(
    type_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    type_alias: &hir::TypeAlias,
) {
    let alias_name = type_alias.name(ctx.db).to_string();

    let snippet = format!("type {} = ", alias_name);

    let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end());

    CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
        .text_edit(TextEdit::replace(range, snippet))
        .lookup_by(alias_name)
        .kind(CompletionItemKind::TypeAlias)
        .set_documentation(type_alias.docs(ctx.db))
        .add_to(acc);
}

fn add_const_impl(
    const_def_node: &SyntaxNode,
    acc: &mut Completions,
    ctx: &CompletionContext,
    const_: &hir::Const,
) {
    let const_name = const_.name(ctx.db).map(|n| n.to_string());

    if let Some(const_name) = const_name {
        let snippet = make_const_compl_syntax(&const_.source(ctx.db).value);

        let range =
            TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end());

        CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
            .text_edit(TextEdit::replace(range, snippet))
            .lookup_by(const_name)
            .kind(CompletionItemKind::Const)
            .set_documentation(const_.docs(ctx.db))
            .add_to(acc);
    }
}

fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
    let const_ = edit::strip_attrs_and_docs(const_);

    let const_start = const_.syntax().text_range().start();
    let const_end = const_.syntax().text_range().end();

    let start =
        const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());

    let end = const_
        .syntax()
        .children_with_tokens()
        .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ)
        .map_or(const_end, |f| f.text_range().start());

    let len = end - start;
    let range = TextRange::from_to(0.into(), len);

    let syntax = const_.syntax().text().slice(range).to_string();

    format!("{} = ", syntax.trim_end())
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn complete(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Magic)
    }

    #[test]
    fn single_function() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [141; 142),
                delete: [138; 142),
                insert: "fn foo() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn hide_implemented_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo();
                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {}

                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo_bar()",
                source_range: [200; 201),
                delete: [197; 201),
                insert: "fn foo_bar() {}",
                kind: Function,
                lookup: "foo_bar",
            },
        ]
        "###);
    }

    #[test]
    fn completes_only_on_top_level() {
        let completions = complete(
            r"
            trait Test {
                fn foo();

                fn foo_bar();
            }

            struct T1;

            impl Test for T1 {
                fn foo() {
                    <|>
                }
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"[]"###);
    }

    #[test]
    fn generic_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>();
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [144; 145),
                delete: [141; 145),
                insert: "fn foo<T>() {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn generic_constrait_fn() {
        let completions = complete(
            r"
            trait Test {
                fn foo<T>() where T: Into<String>;
            }

            struct T1;

            impl Test for T1 {
                fn f<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "fn foo()",
                source_range: [166; 167),
                delete: [163; 167),
                insert: "fn foo<T>()\nwhere T: Into<String> {}",
                kind: Function,
                lookup: "foo",
            },
        ]
        "###);
    }

    #[test]
    fn associated_type() {
        let completions = complete(
            r"
            trait Test {
                type SomeType;
            }

            impl Test for () {
                type S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "type SomeType = ",
                source_range: [124; 125),
                delete: [119; 125),
                insert: "type SomeType = ",
                kind: TypeAlias,
                lookup: "SomeType",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [133; 134),
                delete: [127; 134),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }

    #[test]
    fn associated_const_with_default() {
        let completions = complete(
            r"
            trait Test {
                const SOME_CONST: u16 = 42;
            }

            impl Test for () {
                const S<|>
            }
            ",
        );
        assert_debug_snapshot!(completions, @r###"
        [
            CompletionItem {
                label: "const SOME_CONST: u16 = ",
                source_range: [138; 139),
                delete: [132; 139),
                insert: "const SOME_CONST: u16 = ",
                kind: Const,
                lookup: "SOME_CONST",
            },
        ]
        "###);
    }
}
<|endoftext|>


<commit_before>use hubcaps::gists::{self, Content, GistOptions};
use hubcaps::{Credentials, Github};
use std::collections::HashMap;
use tokio_core::reactor::{Core, Handle};
use hyper;
use hyper_tls;

const FILENAME: &str = "playground.rs";
const DESCRIPTION: &str = "Code shared from the Rust Playground";

pub struct Gist {
    pub id: String,
    pub url: String,
    pub code: String,
}

impl From<gists::Gist> for Gist {
    fn from(other: gists::Gist) -> Self {
        let mut files: Vec<_> = other.files
            .into_iter()
            .map(|(name, file)| (name, file.content.unwrap_or_default()))
            .collect();

        files.sort_by(|&(ref name1, _), &(ref name2, _)| name1.cmp(name2));

        let code = match files.len() {
            0 | 1 => files.into_iter().map(|(_, content)| content).collect(),
            _ => {
                files
                    .into_iter()
                    .map(|(name, content)| format!("// ${}\n\n{}\n\n", name, content))
                    .collect()
            }
        };

        Gist {
            id: other.id,
            url: other.html_url,
            code: code,
        }
    }
}

pub fn create(token: String, code: String) -> Gist {
    let mut core = core();
    let github = github(token, &core.handle());

    let file = Content {
        filename: None,
        content: code,
    };

    let mut files = HashMap::new();
    files.insert(FILENAME.into(), file);

    let options = GistOptions {
        description: Some(DESCRIPTION.into()),
        public: Some(true),
        files,
    };

    let creation = github.gists().create(&options);

    // TODO: Better reporting of failures
    let gist = core.run(creation).expect("Unable to create gist");

    gist.into()
}

pub fn load(token: String, id: &str) -> Gist {
    let mut core = core();
    let github = github(token, &core.handle());

    let loading = github.gists().get(id);

    // TODO: Better reporting of a 404
    let gist = core.run(loading).expect("Unable to load gist");

    gist.into()
}

fn core() -> Core {
    Core::new().expect("Unable to create the reactor")
}

type HubcapConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;

fn github(token: String, handle: &Handle) -> Github<HubcapConnector> {
    Github::new(
        String::from("The Rust Playground"),
        Some(Credentials::Token(token)),
        handle,
    )
}
<commit_msg>Remove second unneeded dollar sign<commit_after>use hubcaps::gists::{self, Content, GistOptions};
use hubcaps::{Credentials, Github};
use std::collections::HashMap;
use tokio_core::reactor::{Core, Handle};
use hyper;
use hyper_tls;

const FILENAME: &str = "playground.rs";
const DESCRIPTION: &str = "Code shared from the Rust Playground";

pub struct Gist {
    pub id: String,
    pub url: String,
    pub code: String,
}

impl From<gists::Gist> for Gist {
    fn from(other: gists::Gist) -> Self {
        let mut files: Vec<_> = other.files
            .into_iter()
            .map(|(name, file)| (name, file.content.unwrap_or_default()))
            .collect();

        files.sort_by(|&(ref name1, _), &(ref name2, _)| name1.cmp(name2));

        let code = match files.len() {
            0 | 1 => files.into_iter().map(|(_, content)| content).collect(),
            _ => {
                files
                    .into_iter()
                    .map(|(name, content)| format!("// {}\n\n{}\n\n", name, content))
                    .collect()
            }
        };

        Gist {
            id: other.id,
            url: other.html_url,
            code: code,
        }
    }
}

pub fn create(token: String, code: String) -> Gist {
    let mut core = core();
    let github = github(token, &core.handle());

    let file = Content {
        filename: None,
        content: code,
    };

    let mut files = HashMap::new();
    files.insert(FILENAME.into(), file);

    let options = GistOptions {
        description: Some(DESCRIPTION.into()),
        public: Some(true),
        files,
    };

    let creation = github.gists().create(&options);

    // TODO: Better reporting of failures
    let gist = core.run(creation).expect("Unable to create gist");

    gist.into()
}

pub fn load(token: String, id: &str) -> Gist {
    let mut core = core();
    let github = github(token, &core.handle());

    let loading = github.gists().get(id);

    // TODO: Better reporting of a 404
    let gist = core.run(loading).expect("Unable to load gist");

    gist.into()
}

fn core() -> Core {
    Core::new().expect("Unable to create the reactor")
}

type HubcapConnector = hyper_tls::HttpsConnector<hyper::client::HttpConnector>;

fn github(token: String, handle: &Handle) -> Github<HubcapConnector> {
    Github::new(
        String::from("The Rust Playground"),
        Some(Credentials::Token(token)),
        handle,
    )
}
<|endoftext|>


<commit_before>use crate::utils::{differing_macro_contexts, in_macro_or_desugar, snippet_opt, span_note_and_lint};
use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::ast;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

declare_lint_pass!(Formatting => [
    SUSPICIOUS_ASSIGNMENT_FORMATTING,
    SUSPICIOUS_ELSE_FORMATTING,
    POSSIBLE_MISSING_COMMA
]);

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro_or_desugar(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if_chain! {
        if let Some((then, &Some(ref else_))) = unsugar_if(expr);
        if is_block(else_) || unsugar_if(else_).is_some();
        if !differing_macro_contexts(then.span, else_.span);
        if !in_macro_or_desugar(then.span) && !in_external_macro(cx.sess, expr.span);

        // workaround for rust-lang/rust#43081
        if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;

        // this will be a span from the closing ‘}’ of the “then” block (excluding) to
        // the “if” of the “else if” block (excluding)
        let else_span = then.span.between(else_.span);

        // the snippet should look like " else \n    " with maybe comments anywhere
        // it’s bad when there is a ‘\n’ after the “else”
        if let Some(else_snippet) = snippet_opt(cx, else_span);
        if let Some(else_pos) = else_snippet.find("else");
        if else_snippet[else_pos..].contains('\n');
        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

        then {
            span_note_and_lint(
                cx,
                SUSPICIOUS_ELSE_FORMATTING,
                else_span,
                &format!("this is an `else {}` but the formatting might hide it", else_desc),
                else_span,
                &format!(
                    "to remove this lint, remove the `else` or remove the new line between \
                     `else` and `{}`",
                    else_desc,
                ),
            );
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro_or_desugar(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) => Some((then, else_)),
        _ => None,
    }
}
<commit_msg>Put 'if let' back into comment.<commit_after>use crate::utils::{differing_macro_contexts, in_macro_or_desugar, snippet_opt, span_note_and_lint};
use if_chain::if_chain;
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::ast;
use syntax::ptr::P;

declare_clippy_lint! {
    /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
    /// operators.
    ///
    /// **Why is this bad?** This is either a typo of `*=`, `!=` or `-=` or
    /// confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
    /// ```
    pub SUSPICIOUS_ASSIGNMENT_FORMATTING,
    style,
    "suspicious formatting of `*=`, `-=` or `!=`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for formatting of `else`. It lints if the `else`
    /// is followed immediately by a newline or the `else` seems to be missing.
    ///
    /// **Why is this bad?** This is probably some refactoring remnant, even if the
    /// code is correct, it might look confusing.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// if foo {
    /// } { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } if bar { // looks like an `else` is missing here
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// { // this is the `else` block of the previous `if`, but should it be?
    /// }
    ///
    /// if foo {
    /// } else
    ///
    /// if bar { // this is the `else` block of the previous `if`, but should it be?
    /// }
    /// ```
    pub SUSPICIOUS_ELSE_FORMATTING,
    style,
    "suspicious formatting of `else`"
}

declare_clippy_lint! {
    /// **What it does:** Checks for possible missing comma in an array. It lints if
    /// an array element is a binary operator expression and it lies on two lines.
    ///
    /// **Why is this bad?** This could lead to unexpected results.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,ignore
    /// let a = &[
    ///     -1, -2, -3 // <= no comma here
    ///     -4, -5, -6
    /// ];
    /// ```
    pub POSSIBLE_MISSING_COMMA,
    correctness,
    "possible missing comma in array"
}

declare_lint_pass!(Formatting => [
    SUSPICIOUS_ASSIGNMENT_FORMATTING,
    SUSPICIOUS_ELSE_FORMATTING,
    POSSIBLE_MISSING_COMMA
]);

impl EarlyLintPass for Formatting {
    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
        for w in block.stmts.windows(2) {
            match (&w[0].node, &w[1].node) {
                (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
                | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
                    check_missing_else(cx, first, second);
                },
                _ => (),
            }
        }
    }

    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
        check_assign(cx, expr);
        check_else(cx, expr);
        check_array(cx, expr);
    }
}

/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Assign(ref lhs, ref rhs) = expr.node {
        if !differing_macro_contexts(lhs.span, rhs.span) && !in_macro_or_desugar(lhs.span) {
            let eq_span = lhs.span.between(rhs.span);
            if let ast::ExprKind::Unary(op, ref sub_rhs) = rhs.node {
                if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
                    let op = ast::UnOp::to_string(op);
                    let eqop_span = lhs.span.between(sub_rhs.span);
                    if eq_snippet.ends_with('=') {
                        span_note_and_lint(
                            cx,
                            SUSPICIOUS_ASSIGNMENT_FORMATTING,
                            eqop_span,
                            &format!(
                                "this looks like you are trying to use `.. {op}= ..`, but you \
                                 really are doing `.. = ({op} ..)`",
                                op = op
                            ),
                            eqop_span,
                            &format!("to remove this lint, use either `{op}=` or `= {op}`", op = op),
                        );
                    }
                }
            }
        }
    }
}

/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`.
fn check_else(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if_chain! {
        if let Some((then, &Some(ref else_))) = unsugar_if(expr);
        if is_block(else_) || unsugar_if(else_).is_some();
        if !differing_macro_contexts(then.span, else_.span);
        if !in_macro_or_desugar(then.span) && !in_external_macro(cx.sess, expr.span);

        // workaround for rust-lang/rust#43081
        if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;

        // this will be a span from the closing ‘}’ of the “then” block (excluding) to
        // the “if” of the “else if” block (excluding)
        let else_span = then.span.between(else_.span);

        // the snippet should look like " else \n    " with maybe comments anywhere
        // it’s bad when there is a ‘\n’ after the “else”
        if let Some(else_snippet) = snippet_opt(cx, else_span);
        if let Some(else_pos) = else_snippet.find("else");
        if else_snippet[else_pos..].contains('\n');
        let else_desc = if unsugar_if(else_).is_some() { "if" } else { "{..}" };

        then {
            span_note_and_lint(
                cx,
                SUSPICIOUS_ELSE_FORMATTING,
                else_span,
                &format!("this is an `else {}` but the formatting might hide it", else_desc),
                else_span,
                &format!(
                    "to remove this lint, remove the `else` or remove the new line between \
                     `else` and `{}`",
                    else_desc,
                ),
            );
        }
    }
}

fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
    // &, *, -
    bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
}

/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
    if let ast::ExprKind::Array(ref array) = expr.node {
        for element in array {
            if let ast::ExprKind::Binary(ref op, ref lhs, _) = element.node {
                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span) {
                    let space_span = lhs.span.between(op.span);
                    if let Some(space_snippet) = snippet_opt(cx, space_span) {
                        let lint_span = lhs.span.with_lo(lhs.span.hi());
                        if space_snippet.contains('\n') {
                            span_note_and_lint(
                                cx,
                                POSSIBLE_MISSING_COMMA,
                                lint_span,
                                "possibly missing a comma here",
                                lint_span,
                                "to remove this lint, add a comma or write the expr in a single line",
                            );
                        }
                    }
                }
            }
        }
    }
}

fn check_missing_else(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
    if !differing_macro_contexts(first.span, second.span)
        && !in_macro_or_desugar(first.span)
        && unsugar_if(first).is_some()
        && (is_block(second) || unsugar_if(second).is_some())
    {
        // where the else would be
        let else_span = first.span.between(second.span);

        if let Some(else_snippet) = snippet_opt(cx, else_span) {
            if !else_snippet.contains('\n') {
                let (looks_like, next_thing) = if unsugar_if(second).is_some() {
                    ("an `else if`", "the second `if`")
                } else {
                    ("an `else {..}`", "the next block")
                };

                span_note_and_lint(
                    cx,
                    SUSPICIOUS_ELSE_FORMATTING,
                    else_span,
                    &format!("this looks like {} but the `else` is missing", looks_like),
                    else_span,
                    &format!(
                        "to remove this lint, add the missing `else` or add a new line before {}",
                        next_thing,
                    ),
                );
            }
        }
    }
}

fn is_block(expr: &ast::Expr) -> bool {
    if let ast::ExprKind::Block(..) = expr.node {
        true
    } else {
        false
    }
}

/// Match `if` or `if let` expressions and return the `then` and `else` block.
fn unsugar_if(expr: &ast::Expr) -> Option<(&P<ast::Block>, &Option<P<ast::Expr>>)> {
    match expr.node {
        ast::ExprKind::If(_, ref then, ref else_) => Some((then, else_)),
        _ => None,
    }
}
<|endoftext|>


<commit_before>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! Additionally, there are 2 environment variables that are supported to
//! constitute license acceptance. Setting HAB_LICENSE to "accept" will
//! accept the license and persist the file and setting HAB_LICENSE to
//! "accept-no-persist" will accept the license but not persist the
//! acceptance.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::prelude::*;
use dirs;
use serde_yaml;
use std::{env,
          fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";
const LICENSE_ACCEPT_ENVVAR: &str = "HAB_LICENSE";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance() -> Result<bool> {
    if license_exists() || env_var_present()? {
        return Ok(true);
    }

    Ok(false)
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if check_for_license_acceptance()? {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    write_license_file()?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn superuser_license_root() -> PathBuf { PathBuf::from(&*FS_ROOT_PATH).join("hab") }

fn user_license_root() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    }
}

fn license_path(root_path: &PathBuf) -> PathBuf { root_path.join("accepted-licenses") }

fn license_file(license_path: &PathBuf) -> PathBuf { license_path.join("habitat") }

fn writeable_license_path() -> PathBuf {
    let root_dir = if am_i_root() {
        superuser_license_root()
    } else {
        user_license_root()
    };

    license_path(&root_dir)
}

fn env_var_present() -> Result<bool> {
    match env::var(LICENSE_ACCEPT_ENVVAR) {
        Ok(val) => {
            if &val == "accept" {
                write_license_file()?;
                Ok(true)
            } else if &val == "accept-no-persist" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        Err(_) => Ok(false),
    }
}

fn write_license_file() -> Result<()> {
    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(writeable_license_path())?;
    let mut file = File::create(license_file(&writeable_license_path()))?;
    file.write_all(content.as_bytes())?;
    Ok(())
}

pub fn license_exists() -> bool {
    license_file(&license_path(&user_license_root())).is_file()
    || license_file(&license_path(&superuser_license_root())).is_file()
}
<commit_msg>hab: Use explicit chrono imports<commit_after>//! This module provides the logic necessary to implement a license prompt into
//! the hab CLI. When a user runs hab for the first time, they will be prompted
//! to accept the Chef license agreement. If they choose not to, then hab will
//! exit and they will be unable to use the tool.
//!
//! Choosing to accept the license will write a file to either
//! /hab/accepted-licenses/habitat (if run as root) or
//! ~/.hab/accepted-licenses/habitat. The presence of this file will
//! prevent further license prompts. The file itself contains various metadata
//! that we collect, but it's important to note that the contents of this file
//! are not strictly important. The important thing is the presence of the file.
//!
//! If a user was to read our code and pre-emptively create one of the above
//! files and leave its contents completely empty, that is sufficient for the
//! acceptance of the license. We will not overwrite their empty file, nor
//! will we care that it is empty.
//!
//! Because of this, the metadata that we store is not strictly necessary and
//! is more of a best effort scenario. If we can't collect all of it for
//! whatever reason, it's fine.
//!
//! Additionally, there are 2 environment variables that are supported to
//! constitute license acceptance. Setting HAB_LICENSE to "accept" will
//! accept the license and persist the file and setting HAB_LICENSE to
//! "accept-no-persist" will accept the license but not persist the
//! acceptance.
//!
//! More detailed information on the license spec is available at
//! https://github.com/chef/license-acceptance

use crate::{common::ui::{self,
                         UIReader,
                         UIWriter,
                         UI},
            error::{Error,
                    Result},
            hcore::{fs::{am_i_root,
                         FS_ROOT_PATH},
                    users::get_current_username}};
use chrono::{DateTime,
             Utc};
use dirs;
use serde_yaml;
use std::{env,
          fs::{self,
               File},
          io::Write,
          path::PathBuf};

const LICENSE_FILE_FORMAT_VERSION: &str = "1.0";
const LICENSE_ACCEPT_ENVVAR: &str = "HAB_LICENSE";

#[derive(Debug, Serialize, Deserialize)]
pub struct LicenseData {
    pub date_accepted: DateTime<Utc>,
    pub accepting_product: String,
    pub accepting_product_version: String,
    pub user: Option<String>,
    pub file_format: String,
}

impl LicenseData {
    pub fn new() -> Self {
        LicenseData { date_accepted: Utc::now(),
                      accepting_product: String::from("hab"),
                      accepting_product_version: super::VERSION.to_string(),
                      user: get_current_username(),
                      file_format: String::from(LICENSE_FILE_FORMAT_VERSION), }
    }
}

pub fn check_for_license_acceptance() -> Result<bool> {
    if license_exists() || env_var_present()? {
        return Ok(true);
    }

    Ok(false)
}

pub fn check_for_license_acceptance_and_prompt(ui: &mut UI) -> Result<()> {
    if check_for_license_acceptance()? {
        return Ok(());
    }

    ui.heading("+---------------------------------------------+")?;
    ui.heading("            Chef License Acceptance")?;
    ui.br()?;
    ui.info("Before you can continue, 1 product license must be accepted.")?;
    ui.info("View the license at https://www.chef.io/end-user-license-agreement")?;
    ui.br()?;
    ui.info("License that needs accepting:")?;
    ui.br()?;
    ui.info("  * Habitat")?;
    ui.br()?;

    if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
        accept_license(ui)
    } else {
        ui.br()?;
        ui.info("If you do not accept this license you will not be able to use Chef products.")?;
        ui.br()?;

        if ui.prompt_yes_no("Do you accept the 1 product license?", Some(false))? {
            accept_license(ui)
        } else {
            ui.br()?;
            ui.heading("+---------------------------------------------+")?;
            Err(Error::LicenseNotAccepted)
        }
    }
}

pub fn accept_license(ui: &mut UI) -> Result<()> {
    if license_exists() {
        ui.info("You have already accepted the license.")?;
        return Ok(());
    }

    ui.br()?;
    ui.info("Accepting 1 product license...")?;

    write_license_file()?;

    ui.status(ui::Status::Custom(ui::Glyph::CheckMark, String::from("")),
              "1 product license accepted.")?;
    ui.br()?;
    ui.heading("+---------------------------------------------+")?;

    Ok(())
}

fn superuser_license_root() -> PathBuf { PathBuf::from(&*FS_ROOT_PATH).join("hab") }

fn user_license_root() -> PathBuf {
    if let Some(home) = dirs::home_dir() {
        home.join(".hab")
    } else {
        panic!("No home directory available. Unable to find a suitable place to write a license \
                file.");
    }
}

fn license_path(root_path: &PathBuf) -> PathBuf { root_path.join("accepted-licenses") }

fn license_file(license_path: &PathBuf) -> PathBuf { license_path.join("habitat") }

fn writeable_license_path() -> PathBuf {
    let root_dir = if am_i_root() {
        superuser_license_root()
    } else {
        user_license_root()
    };

    license_path(&root_dir)
}

fn env_var_present() -> Result<bool> {
    match env::var(LICENSE_ACCEPT_ENVVAR) {
        Ok(val) => {
            if &val == "accept" {
                write_license_file()?;
                Ok(true)
            } else if &val == "accept-no-persist" {
                Ok(true)
            } else {
                Ok(false)
            }
        }
        Err(_) => Ok(false),
    }
}

fn write_license_file() -> Result<()> {
    let license = LicenseData::new();
    let content = serde_yaml::to_string(&license)?;
    fs::create_dir_all(writeable_license_path())?;
    let mut file = File::create(license_file(&writeable_license_path()))?;
    file.write_all(content.as_bytes())?;
    Ok(())
}

pub fn license_exists() -> bool {
    license_file(&license_path(&user_license_root())).is_file()
    || license_file(&license_path(&superuser_license_root())).is_file()
}
<|endoftext|>