<commit_before>// Copyright 2016 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.

// ignore-wasm32-bare compiled with panic=abort by default

#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)]

use std::cell::{Cell, RefCell};
use std::ops::Generator;
use std::panic;
use std::usize;

struct InjectedFailure;

struct Allocator {
    data: RefCell<Vec<bool>>,
    failing_op: usize,
    cur_ops: Cell<usize>,
}

impl panic::UnwindSafe for Allocator {}
impl panic::RefUnwindSafe for Allocator {}

impl Drop for Allocator {
    fn drop(&mut self) {
        let data = self.data.borrow();
        if data.iter().any(|d| *d) {
            panic!("missing free: {:?}", data);
        }
    }
}

impl Allocator {
    fn new(failing_op: usize) -> Self {
        Allocator {
            failing_op: failing_op,
            cur_ops: Cell::new(0),
            data: RefCell::new(vec![])
        }
    }
    fn alloc(&self) -> Ptr {
        self.cur_ops.set(self.cur_ops.get() + 1);

        if self.cur_ops.get() == self.failing_op {
            panic!(InjectedFailure);
        }

        let mut data = self.data.borrow_mut();
        let addr = data.len();
        data.push(true);
        Ptr(addr, self)
    }
}

struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
    fn drop(&mut self) {
        match self.1.data.borrow_mut()[self.0] {
            false => {
                panic!("double free at index {:?}", self.0)
            }
            ref mut d => *d = false
        }

        self.1.cur_ops.set(self.1.cur_ops.get()+1);

        if self.1.cur_ops.get() == self.1.failing_op {
            panic!(InjectedFailure);
        }
    }
}

fn dynamic_init(a: &Allocator, c: bool) {
    let _x;
    if c {
        _x = Some(a.alloc());
    }
}

fn dynamic_drop(a: &Allocator, c: bool) {
    let x = a.alloc();
    if c {
        Some(x)
    } else {
        None
    };
}

struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
    for i in 0..2 {
        let x;
        let y;
        if (c0 && i == 0) || (c1 && i == 1) {
            x = (a.alloc(), a.alloc(), a.alloc());
            y = TwoPtrs(a.alloc(), a.alloc());
            if c {
                drop(x.1);
                drop(y.0);
            }
        }
    }
}

fn field_assignment(a: &Allocator, c0: bool) {
    let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc());

    x.1 = a.alloc();
    x.1 = a.alloc();

    let f = (x.0).0;
    if c0 {
        (x.0).0 = f;
    }
}

fn assignment2(a: &Allocator, c0: bool, c1: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
    if c1 {
        _w = a.alloc();
    }
}

fn assignment1(a: &Allocator, c0: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
}

#[allow(unions_with_drop_fields)]
union Boxy<T> {
    a: T,
    b: T,
}

fn union1(a: &Allocator) {
    unsafe {
        let mut u = Boxy { a: a.alloc() };
        u.b = a.alloc();
        drop(u.a);
    }
}

fn array_simple(a: &Allocator) {
    let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn vec_simple(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn generator(a: &Allocator, run_count: usize) {
    assert!(run_count < 4);

    let mut gen = || {
        (a.alloc(),
         yield a.alloc(),
         a.alloc(),
         yield a.alloc()
         );
    };
    for _ in 0..run_count {
        gen.resume();
    }
}

fn mixed_drop_and_nondrop(a: &Allocator) {
    // check that destructor panics handle drop
    // and non-drop blocks in the same scope correctly.
    //
    // Surprisingly enough, this used to not work.
    let (x, y, z);
    x = a.alloc();
    y = 5;
    z = a.alloc();
}

#[allow(unreachable_code)]
fn vec_unreachable(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
}

fn slice_pattern_first(a: &Allocator) {
    let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_middle(a: &Allocator) {
    let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_two(a: &Allocator) {
    let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_last(a: &Allocator) {
    let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_one_of(a: &Allocator, i: usize) {
    let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
    let _x = match i {
        0 => { let [a, ..] = array; a }
        1 => { let [_, a, ..] = array; a }
        2 => { let [_, _, a, _] = array; a }
        3 => { let [_, _, _, a] = array; a }
        _ => panic!("unmatched"),
    };
}

fn run_test<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);

    for failing_op in 1..first_alloc.cur_ops.get()+1 {
        let alloc = Allocator::new(failing_op);
        let alloc = &alloc;
        let f = panic::AssertUnwindSafe(&mut f);
        let result = panic::catch_unwind(move || {
            f.0(alloc);
        });
        match result {
            Ok(..) => panic!("test executed {} ops but now {}",
                             first_alloc.cur_ops.get(), alloc.cur_ops.get()),
            Err(e) => {
                if e.downcast_ref::<InjectedFailure>().is_none() {
                    panic::resume_unwind(e);
                }
            }
        }
    }
}

fn run_test_nopanic<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);
}

fn main() {
    run_test(|a| dynamic_init(a, false));
    run_test(|a| dynamic_init(a, true));
    run_test(|a| dynamic_drop(a, false));
    run_test(|a| dynamic_drop(a, true));

    run_test(|a| assignment2(a, false, false));
    run_test(|a| assignment2(a, false, true));
    run_test(|a| assignment2(a, true, false));
    run_test(|a| assignment2(a, true, true));

    run_test(|a| assignment1(a, false));
    run_test(|a| assignment1(a, true));

    run_test(|a| array_simple(a));
    run_test(|a| vec_simple(a));
    run_test(|a| vec_unreachable(a));

    run_test(|a| struct_dynamic_drop(a, false, false, false));
    run_test(|a| struct_dynamic_drop(a, false, false, true));
    run_test(|a| struct_dynamic_drop(a, false, true, false));
    run_test(|a| struct_dynamic_drop(a, false, true, true));
    run_test(|a| struct_dynamic_drop(a, true, false, false));
    run_test(|a| struct_dynamic_drop(a, true, false, true));
    run_test(|a| struct_dynamic_drop(a, true, true, false));
    run_test(|a| struct_dynamic_drop(a, true, true, true));

    run_test(|a| field_assignment(a, false));
    run_test(|a| field_assignment(a, true));

    run_test(|a| generator(a, 0));
    run_test(|a| generator(a, 1));
    run_test(|a| generator(a, 2));
    run_test(|a| generator(a, 3));

    run_test(|a| mixed_drop_and_nondrop(a));

    run_test(|a| slice_pattern_first(a));
    run_test(|a| slice_pattern_middle(a));
    run_test(|a| slice_pattern_two(a));
    run_test(|a| slice_pattern_last(a));
    run_test(|a| slice_pattern_one_of(a, 0));
    run_test(|a| slice_pattern_one_of(a, 1));
    run_test(|a| slice_pattern_one_of(a, 2));
    run_test(|a| slice_pattern_one_of(a, 3));

    run_test_nopanic(|a| union1(a));
}
<commit_msg>Rollup merge of #47662 - spastorino:add_test_to_nll, r=nikomatsakis<commit_after>// Copyright 2016 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.

// revisions:lexical nll
#![cfg_attr(nll, feature(nll))]

// ignore-wasm32-bare compiled with panic=abort by default

#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)]

use std::cell::{Cell, RefCell};
use std::ops::Generator;
use std::panic;
use std::usize;

struct InjectedFailure;

struct Allocator {
    data: RefCell<Vec<bool>>,
    failing_op: usize,
    cur_ops: Cell<usize>,
}

impl panic::UnwindSafe for Allocator {}
impl panic::RefUnwindSafe for Allocator {}

impl Drop for Allocator {
    fn drop(&mut self) {
        let data = self.data.borrow();
        if data.iter().any(|d| *d) {
            panic!("missing free: {:?}", data);
        }
    }
}

impl Allocator {
    fn new(failing_op: usize) -> Self {
        Allocator {
            failing_op: failing_op,
            cur_ops: Cell::new(0),
            data: RefCell::new(vec![])
        }
    }
    fn alloc(&self) -> Ptr {
        self.cur_ops.set(self.cur_ops.get() + 1);

        if self.cur_ops.get() == self.failing_op {
            panic!(InjectedFailure);
        }

        let mut data = self.data.borrow_mut();
        let addr = data.len();
        data.push(true);
        Ptr(addr, self)
    }
}

struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
    fn drop(&mut self) {
        match self.1.data.borrow_mut()[self.0] {
            false => {
                panic!("double free at index {:?}", self.0)
            }
            ref mut d => *d = false
        }

        self.1.cur_ops.set(self.1.cur_ops.get()+1);

        if self.1.cur_ops.get() == self.1.failing_op {
            panic!(InjectedFailure);
        }
    }
}

fn dynamic_init(a: &Allocator, c: bool) {
    let _x;
    if c {
        _x = Some(a.alloc());
    }
}

fn dynamic_drop(a: &Allocator, c: bool) {
    let x = a.alloc();
    if c {
        Some(x)
    } else {
        None
    };
}

struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
    for i in 0..2 {
        let x;
        let y;
        if (c0 && i == 0) || (c1 && i == 1) {
            x = (a.alloc(), a.alloc(), a.alloc());
            y = TwoPtrs(a.alloc(), a.alloc());
            if c {
                drop(x.1);
                drop(y.0);
            }
        }
    }
}

fn field_assignment(a: &Allocator, c0: bool) {
    let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc());

    x.1 = a.alloc();
    x.1 = a.alloc();

    let f = (x.0).0;
    if c0 {
        (x.0).0 = f;
    }
}

fn assignment2(a: &Allocator, c0: bool, c1: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
    if c1 {
        _w = a.alloc();
    }
}

fn assignment1(a: &Allocator, c0: bool) {
    let mut _v = a.alloc();
    let mut _w = a.alloc();
    if c0 {
        drop(_v);
    }
    _v = _w;
}

#[allow(unions_with_drop_fields)]
union Boxy<T> {
    a: T,
    b: T,
}

fn union1(a: &Allocator) {
    unsafe {
        let mut u = Boxy { a: a.alloc() };
        u.b = a.alloc();
        drop(u.a);
    }
}

fn array_simple(a: &Allocator) {
    let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn vec_simple(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn generator(a: &Allocator, run_count: usize) {
    assert!(run_count < 4);

    let mut gen = || {
        (a.alloc(),
         yield a.alloc(),
         a.alloc(),
         yield a.alloc()
         );
    };
    for _ in 0..run_count {
        gen.resume();
    }
}

fn mixed_drop_and_nondrop(a: &Allocator) {
    // check that destructor panics handle drop
    // and non-drop blocks in the same scope correctly.
    //
    // Surprisingly enough, this used to not work.
    let (x, y, z);
    x = a.alloc();
    y = 5;
    z = a.alloc();
}

#[allow(unreachable_code)]
fn vec_unreachable(a: &Allocator) {
    let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
}

fn slice_pattern_first(a: &Allocator) {
    let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_middle(a: &Allocator) {
    let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_two(a: &Allocator) {
    let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_last(a: &Allocator) {
    let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
}

fn slice_pattern_one_of(a: &Allocator, i: usize) {
    let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
    let _x = match i {
        0 => { let [a, ..] = array; a }
        1 => { let [_, a, ..] = array; a }
        2 => { let [_, _, a, _] = array; a }
        3 => { let [_, _, _, a] = array; a }
        _ => panic!("unmatched"),
    };
}

fn run_test<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);

    for failing_op in 1..first_alloc.cur_ops.get()+1 {
        let alloc = Allocator::new(failing_op);
        let alloc = &alloc;
        let f = panic::AssertUnwindSafe(&mut f);
        let result = panic::catch_unwind(move || {
            f.0(alloc);
        });
        match result {
            Ok(..) => panic!("test executed {} ops but now {}",
                             first_alloc.cur_ops.get(), alloc.cur_ops.get()),
            Err(e) => {
                if e.downcast_ref::<InjectedFailure>().is_none() {
                    panic::resume_unwind(e);
                }
            }
        }
    }
}

fn run_test_nopanic<F>(mut f: F)
    where F: FnMut(&Allocator)
{
    let first_alloc = Allocator::new(usize::MAX);
    f(&first_alloc);
}

fn main() {
    run_test(|a| dynamic_init(a, false));
    run_test(|a| dynamic_init(a, true));
    run_test(|a| dynamic_drop(a, false));
    run_test(|a| dynamic_drop(a, true));

    run_test(|a| assignment2(a, false, false));
    run_test(|a| assignment2(a, false, true));
    run_test(|a| assignment2(a, true, false));
    run_test(|a| assignment2(a, true, true));

    run_test(|a| assignment1(a, false));
    run_test(|a| assignment1(a, true));

    run_test(|a| array_simple(a));
    run_test(|a| vec_simple(a));
    run_test(|a| vec_unreachable(a));

    run_test(|a| struct_dynamic_drop(a, false, false, false));
    run_test(|a| struct_dynamic_drop(a, false, false, true));
    run_test(|a| struct_dynamic_drop(a, false, true, false));
    run_test(|a| struct_dynamic_drop(a, false, true, true));
    run_test(|a| struct_dynamic_drop(a, true, false, false));
    run_test(|a| struct_dynamic_drop(a, true, false, true));
    run_test(|a| struct_dynamic_drop(a, true, true, false));
    run_test(|a| struct_dynamic_drop(a, true, true, true));

    run_test(|a| field_assignment(a, false));
    run_test(|a| field_assignment(a, true));

    run_test(|a| generator(a, 0));
    run_test(|a| generator(a, 1));
    run_test(|a| generator(a, 2));
    run_test(|a| generator(a, 3));

    run_test(|a| mixed_drop_and_nondrop(a));

    run_test(|a| slice_pattern_first(a));
    run_test(|a| slice_pattern_middle(a));
    run_test(|a| slice_pattern_two(a));
    run_test(|a| slice_pattern_last(a));
    run_test(|a| slice_pattern_one_of(a, 0));
    run_test(|a| slice_pattern_one_of(a, 1));
    run_test(|a| slice_pattern_one_of(a, 2));
    run_test(|a| slice_pattern_one_of(a, 3));

    run_test_nopanic(|a| union1(a));
}
<|endoftext|>


<commit_before>// aux-build:issue_2242_a.rs
// aux-build:issue_2242_b.rs
// aux-build:issue_2242_c.rs

use a;
use b;
use c;

import a::to_str;

fn main() {
    io::println((~"foo").to_str());
    io::println(1.to_str());
    io::println(true.to_str());
}
<commit_msg>xfail-fast issue-2242<commit_after>// xfail-fast (aux-build)
// aux-build:issue_2242_a.rs
// aux-build:issue_2242_b.rs
// aux-build:issue_2242_c.rs

use a;
use b;
use c;

import a::to_str;

fn main() {
    io::println((~"foo").to_str());
    io::println(1.to_str());
    io::println(true.to_str());
}
<|endoftext|>


<commit_before>//! Developer note:
//!
//! This is a set of embed builders for rich embeds.
//!
//! These are used in the [`Context::send_message`] and
//! [`ExecuteWebhook::embeds`] methods, both as part of builders.
//!
//! The only builder that should be exposed is [`CreateEmbed`]. The rest of
//! these have no real reason for being exposed, but are for completeness' sake.
//!
//! Documentation for embeds can be found [here].
//!
//! [`Context::send_message`]: ../../client/struct.Context.html#method.send_message
//! [`CreateEmbed`]: struct.CreateEmbed.html
//! [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
//! [here]: https://discordapp.com/developers/docs/resources/channel#embed-object

use serde_json::builder::ObjectBuilder;
use serde_json::Value;
use std::collections::BTreeMap;
use std::default::Default;
use ::model::Embed;
use ::utils::Colour;

/// A builder to create a fake [`Embed`] object, for use with the
/// [`Context::send_message`] and [`ExecuteWebhook::embeds`] methods.
///
/// # Examples
///
/// Refer to the documentation for [`Context::send_message`] for a very in-depth
/// example on how to use this.
///
/// [`Context::send_message`]: ../../client/struct.Context.html#method.send_message
/// [`Embed`]: ../../model/struct.Embed.html
/// [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
pub struct CreateEmbed(pub BTreeMap<String, Value>);

impl CreateEmbed {
    /// Set the author of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedAuthor`] for more
    /// information.
    ///
    /// [`CreateEmbedAuthor`]: struct.CreateEmbedAuthor.html
    pub fn author<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedAuthor) -> CreateEmbedAuthor {
        let author = f(CreateEmbedAuthor::default()).0.build();

        self.0.insert("author".to_owned(), author);

        CreateEmbed(self.0)
    }

    /// Set the colour of the left-hand side of the embed.
    ///
    /// This is an alias of [`colour`].
    ///
    /// [`colour`]: #method.colour
    pub fn color<C: Into<Colour>>(self, colour: C) -> Self {
        self.colour(colour.into())
    }

    /// Set the colour of the left-hand side of the embed.
    pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
        self.0.insert("color".to_owned(), Value::U64(colour.into().value as u64));

        CreateEmbed(self.0)
    }

    /// Set the description of the embed.
    ///
    /// **Note**: This can't be longer than 2048 characters.
    pub fn description(mut self, description: &str) -> Self {
        self.0.insert("description".to_owned(), Value::String(description.to_owned()));

        CreateEmbed(self.0)
    }

    /// Set a field. Note that this will not overwrite other fields, and will
    /// add to them.
    ///
    /// Refer to the documentation for [`CreateEmbedField`] for more
    /// information.
    ///
    /// **Note**: Maximum amount of characters you can put is 256 in a field
    /// name and 1024 in a field value and a field is inline by default.
    ///
    /// [`CreateEmbedField`]: struct.CreateEmbedField.html
    pub fn field<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedField) -> CreateEmbedField {
        let field = f(CreateEmbedField::default()).0.build();

        {
            let key = "fields".to_owned();

            let entry = self.0.remove(&key).unwrap_or_else(|| Value::Array(vec![]));
            let mut arr = match entry {
                Value::Array(inner) => inner,
                _ => {
                    // The type of `entry` should always be a `Value::Array`.
                    //
                    // Theoretically this never happens, but you never know.
                    //
                    // In the event that it does, just return the current value.
                    return CreateEmbed(self.0);
                },
            };
            arr.push(field);

            self.0.insert("fields".to_owned(), Value::Array(arr));
        }

        CreateEmbed(self.0)
    }

    /// Set the footer of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedFooter`] for more
    /// information.
    ///
    /// [`CreateEmbedFooter`]: struct.CreateEmbedFooter.html
    pub fn footer<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedFooter) -> CreateEmbedFooter {
        let footer = f(CreateEmbedFooter::default()).0.build();

        self.0.insert("footer".to_owned(), footer);

        CreateEmbed(self.0)
    }

    /// Set the image associated with the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedImage`] for more
    /// information.
    ///
    /// [`CreateEmbedImage`]: struct.CreateEmbedImage.html
    pub fn image<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedImage) -> CreateEmbedImage {
        let image = f(CreateEmbedImage::default()).0.build();

        self.0.insert("image".to_owned(), image);

        CreateEmbed(self.0)
    }

    /// Set the thumbnail of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedThumbnail`] for more
    /// information.
    ///
    /// [`CreateEmbedThumbnail`]: struct.CreateEmbedThumbnail.html
    pub fn thumbnail<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedThumbnail) -> CreateEmbedThumbnail {
        let thumbnail = f(CreateEmbedThumbnail::default()).0.build();

        self.0.insert("thumbnail".to_owned(), thumbnail);

        CreateEmbed(self.0)
    }

    /// Set the timestamp.
    ///
    /// **Note:** This timestamp must be in ISO-8601 format.
    ///
    /// # Examples
    ///
    /// `2017-01-03T23:00:00Z`
    /// `2004-06-08T16:04:23-05:00`
    pub fn timestamp(mut self, timestamp: &str) -> Self {
        self.0.insert("timestamp".to_owned(), Value::String(timestamp.to_owned()));

        CreateEmbed(self.0)
    }

    /// Set the title of the embed.
    pub fn title(mut self, title: &str) -> Self {
        self.0.insert("title".to_owned(), Value::String(title.to_owned()));

        CreateEmbed(self.0)
    }

    /// Set the URL to direct to when clicking on the title.
    pub fn url(mut self, url: &str) -> Self {
        self.0.insert("url".to_owned(), Value::String(url.to_owned()));

        CreateEmbed(self.0)
    }
}

impl Default for CreateEmbed {
    /// Creates a builder with default values, setting the `type` to `rich`.
    fn default() -> CreateEmbed {
        let mut map = BTreeMap::new();
        map.insert("type".to_owned(), Value::String("rich".to_owned()));

        CreateEmbed(map)
    }
}

impl From<Embed> for CreateEmbed {
    /// Converts the fields of an embed into the values for a new embed builder.
    ///
    /// Some values - such as Proxy URLs - are not preserved.
    fn from(embed: Embed) -> CreateEmbed {
        let mut b = CreateEmbed::default()
            .colour(embed.colour);

        if let Some(author) = embed.author {
            b = b.author(move |mut a| {
                a = a.name(&author.name);

                if let Some(icon_url) = author.icon_url {
                    a = a.icon_url(&icon_url);
                }

                if let Some(url) = author.url {
                    a = a.url(&url);
                }

                a
            });
        }

        if let Some(description) = embed.description {
            b = b.description(&description);
        }

        if let Some(fields) = embed.fields {
            for field in fields {
                b = b.field(move |f| f
                    .inline(field.inline)
                    .name(&field.name)
                    .value(&field.value));
            }
        }

        if let Some(image) = embed.image {
            b = b.image(move |i| i.url(&image.url));
        }

        if let Some(timestamp) = embed.timestamp {
            b = b.timestamp(&timestamp);
        }

        if let Some(thumbnail) = embed.thumbnail {
            b = b.thumbnail(move |t| t.url(&thumbnail.url));
        }

        if let Some(url) = embed.url {
            b = b.url(&url);
        }

        if let Some(title) = embed.title {
            b = b.title(&title);
        }

        b
    }
}

/// A builder to create a fake [`Embed`] object's author, for use with the
/// [`CreateEmbed::author`] method.
///
/// Requires that you specify a [`name`].
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::author`]: struct.CreateEmbed.html#method.author
/// [`name`]: #method.name
#[derive(Default)]
pub struct CreateEmbedAuthor(pub ObjectBuilder);

impl CreateEmbedAuthor {
    /// Set the URL of the author's icon.
    pub fn icon_url(self, icon_url: &str) -> Self {
        CreateEmbedAuthor(self.0.insert("icon_url", icon_url))
    }

    /// Set the author's name.
    pub fn name(self, name: &str) -> Self {
        CreateEmbedAuthor(self.0.insert("name", name))
    }

    /// Set the author's URL.
    pub fn url(self, url: &str) -> Self {
        CreateEmbedAuthor(self.0.insert("url", url))
    }
}

/// A builder to create a fake [`Embed`] object's field, for use with the
/// [`CreateEmbed::field`] method.
///
/// This does not require any field be set. `inline` is set to `true` by
/// default.
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::field`]: struct.CreateEmbed.html#method.field
pub struct CreateEmbedField(pub ObjectBuilder);

impl CreateEmbedField {
    /// Set whether the field is inlined. Set to true by default.
    pub fn inline(self, inline: bool) -> Self {
        CreateEmbedField(self.0.insert("inline", inline))
    }

    /// Set the field's name. It can't be longer than 256 characters.
    pub fn name(self, name: &str) -> Self {
        CreateEmbedField(self.0.insert("name", name))
    }

    /// Set the field's value. It can't be longer than 1024 characters.
    pub fn value(self, value: &str) -> Self {
        CreateEmbedField(self.0.insert("value", value))
    }
}

impl Default for CreateEmbedField {
    /// Creates a builder with default values, setting the value of `inline` to
    /// `true`.
    fn default() -> CreateEmbedField {
        CreateEmbedField(ObjectBuilder::new().insert("inline", true))
    }
}

/// A builder to create a fake [`Embed`] object's footer, for use with the
/// [`CreateEmbed::footer`] method.
///
/// This does not require any field be set.
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::footer`]: struct.CreateEmbed.html#method.footer
#[derive(Default)]
pub struct CreateEmbedFooter(pub ObjectBuilder);

impl CreateEmbedFooter {
    /// Set the icon URL's value. This only supports HTTP(S).
    pub fn icon_url(self, icon_url: &str) -> Self {
        CreateEmbedFooter(self.0.insert("icon_url", icon_url))
    }

    /// Set the footer's text.
    pub fn text(self, text: &str) -> Self {
        CreateEmbedFooter(self.0.insert("text", text))
    }
}

/// A builder to create a fake [`Embed`] object's image, for use with the
/// [`CreateEmbed::image`] method.
///
/// This does not require any field be set.
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::image`]: struct.CreateEmbed.html#method.image
#[derive(Default)]
pub struct CreateEmbedImage(pub ObjectBuilder);

impl CreateEmbedImage {
    /// Set the display height of the image.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn height(self, height: u64) -> Self {
        CreateEmbedImage(self.0.insert("height", height))
    }

    /// Set the image's URL. This only supports HTTP(S).
    pub fn url(self, url: &str) -> Self {
        CreateEmbedImage(self.0.insert("url", url))
    }

    /// Set the display width of the image.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn width(self, width: u64) -> Self {
        CreateEmbedImage(self.0.insert("width", width))
    }
}

/// A builder to create a fake [`Embed`] object's thumbnail, for use with the
/// [`CreateEmbed::thumbnail`] method.
///
/// Requires that you specify a [`url`].
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::thumbnail`]: struct.CreateEmbed.html#method.thumbnail
/// [`url`]: #method.url
#[derive(Default)]
pub struct CreateEmbedThumbnail(pub ObjectBuilder);

impl CreateEmbedThumbnail {
    /// Set the height of the thumbnail, in pixels.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn height(self, height: u64) -> Self {
        CreateEmbedThumbnail(self.0.insert("height", height))
    }

    /// Set the URL of the thumbnail. This only supports HTTP(S).
    ///
    /// _Must_ be specified.
    pub fn url(self, url: &str) -> Self {
        CreateEmbedThumbnail(self.0.insert("url", url))
    }

    /// Set the width of the thumbnail, in pixels.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn width(self, width: u64) -> Self {
        CreateEmbedThumbnail(self.0.insert("width", width))
    }
}
<commit_msg>No Z or +XX:XX<commit_after>//! Developer note:
//!
//! This is a set of embed builders for rich embeds.
//!
//! These are used in the [`Context::send_message`] and
//! [`ExecuteWebhook::embeds`] methods, both as part of builders.
//!
//! The only builder that should be exposed is [`CreateEmbed`]. The rest of
//! these have no real reason for being exposed, but are for completeness' sake.
//!
//! Documentation for embeds can be found [here].
//!
//! [`Context::send_message`]: ../../client/struct.Context.html#method.send_message
//! [`CreateEmbed`]: struct.CreateEmbed.html
//! [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
//! [here]: https://discordapp.com/developers/docs/resources/channel#embed-object

use serde_json::builder::ObjectBuilder;
use serde_json::Value;
use std::collections::BTreeMap;
use std::default::Default;
use ::model::Embed;
use ::utils::Colour;

/// A builder to create a fake [`Embed`] object, for use with the
/// [`Context::send_message`] and [`ExecuteWebhook::embeds`] methods.
///
/// # Examples
///
/// Refer to the documentation for [`Context::send_message`] for a very in-depth
/// example on how to use this.
///
/// [`Context::send_message`]: ../../client/struct.Context.html#method.send_message
/// [`Embed`]: ../../model/struct.Embed.html
/// [`ExecuteWebhook::embeds`]: struct.ExecuteWebhook.html#method.embeds
pub struct CreateEmbed(pub BTreeMap<String, Value>);

impl CreateEmbed {
    /// Set the author of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedAuthor`] for more
    /// information.
    ///
    /// [`CreateEmbedAuthor`]: struct.CreateEmbedAuthor.html
    pub fn author<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedAuthor) -> CreateEmbedAuthor {
        let author = f(CreateEmbedAuthor::default()).0.build();

        self.0.insert("author".to_owned(), author);

        CreateEmbed(self.0)
    }

    /// Set the colour of the left-hand side of the embed.
    ///
    /// This is an alias of [`colour`].
    ///
    /// [`colour`]: #method.colour
    pub fn color<C: Into<Colour>>(self, colour: C) -> Self {
        self.colour(colour.into())
    }

    /// Set the colour of the left-hand side of the embed.
    pub fn colour<C: Into<Colour>>(mut self, colour: C) -> Self {
        self.0.insert("color".to_owned(), Value::U64(colour.into().value as u64));

        CreateEmbed(self.0)
    }

    /// Set the description of the embed.
    ///
    /// **Note**: This can't be longer than 2048 characters.
    pub fn description(mut self, description: &str) -> Self {
        self.0.insert("description".to_owned(), Value::String(description.to_owned()));

        CreateEmbed(self.0)
    }

    /// Set a field. Note that this will not overwrite other fields, and will
    /// add to them.
    ///
    /// Refer to the documentation for [`CreateEmbedField`] for more
    /// information.
    ///
    /// **Note**: Maximum amount of characters you can put is 256 in a field
    /// name and 1024 in a field value and a field is inline by default.
    ///
    /// [`CreateEmbedField`]: struct.CreateEmbedField.html
    pub fn field<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedField) -> CreateEmbedField {
        let field = f(CreateEmbedField::default()).0.build();

        {
            let key = "fields".to_owned();

            let entry = self.0.remove(&key).unwrap_or_else(|| Value::Array(vec![]));
            let mut arr = match entry {
                Value::Array(inner) => inner,
                _ => {
                    // The type of `entry` should always be a `Value::Array`.
                    //
                    // Theoretically this never happens, but you never know.
                    //
                    // In the event that it does, just return the current value.
                    return CreateEmbed(self.0);
                },
            };
            arr.push(field);

            self.0.insert("fields".to_owned(), Value::Array(arr));
        }

        CreateEmbed(self.0)
    }

    /// Set the footer of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedFooter`] for more
    /// information.
    ///
    /// [`CreateEmbedFooter`]: struct.CreateEmbedFooter.html
    pub fn footer<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedFooter) -> CreateEmbedFooter {
        let footer = f(CreateEmbedFooter::default()).0.build();

        self.0.insert("footer".to_owned(), footer);

        CreateEmbed(self.0)
    }

    /// Set the image associated with the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedImage`] for more
    /// information.
    ///
    /// [`CreateEmbedImage`]: struct.CreateEmbedImage.html
    pub fn image<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedImage) -> CreateEmbedImage {
        let image = f(CreateEmbedImage::default()).0.build();

        self.0.insert("image".to_owned(), image);

        CreateEmbed(self.0)
    }

    /// Set the thumbnail of the embed.
    ///
    /// Refer to the documentation for [`CreateEmbedThumbnail`] for more
    /// information.
    ///
    /// [`CreateEmbedThumbnail`]: struct.CreateEmbedThumbnail.html
    pub fn thumbnail<F>(mut self, f: F) -> Self
        where F: FnOnce(CreateEmbedThumbnail) -> CreateEmbedThumbnail {
        let thumbnail = f(CreateEmbedThumbnail::default()).0.build();

        self.0.insert("thumbnail".to_owned(), thumbnail);

        CreateEmbed(self.0)
    }

    /// Set the timestamp.
    ///
    /// **Note:** This timestamp must be in ISO-8601 format. It must also be
    /// in UTC format.
    ///
    /// # Examples
    ///
    /// `2017-01-03T23:00:00`
    /// `2004-06-08T16:04:23`
    pub fn timestamp(mut self, timestamp: &str) -> Self {
        self.0.insert("timestamp".to_owned(), Value::String(timestamp.to_owned()));

        CreateEmbed(self.0)
    }

    /// Set the title of the embed.
    pub fn title(mut self, title: &str) -> Self {
        self.0.insert("title".to_owned(), Value::String(title.to_owned()));

        CreateEmbed(self.0)
    }

    /// Set the URL to direct to when clicking on the title.
    pub fn url(mut self, url: &str) -> Self {
        self.0.insert("url".to_owned(), Value::String(url.to_owned()));

        CreateEmbed(self.0)
    }
}

impl Default for CreateEmbed {
    /// Creates a builder with default values, setting the `type` to `rich`.
    fn default() -> CreateEmbed {
        let mut map = BTreeMap::new();
        map.insert("type".to_owned(), Value::String("rich".to_owned()));

        CreateEmbed(map)
    }
}

impl From<Embed> for CreateEmbed {
    /// Converts the fields of an embed into the values for a new embed builder.
    ///
    /// Some values - such as Proxy URLs - are not preserved.
    fn from(embed: Embed) -> CreateEmbed {
        let mut b = CreateEmbed::default()
            .colour(embed.colour);

        if let Some(author) = embed.author {
            b = b.author(move |mut a| {
                a = a.name(&author.name);

                if let Some(icon_url) = author.icon_url {
                    a = a.icon_url(&icon_url);
                }

                if let Some(url) = author.url {
                    a = a.url(&url);
                }

                a
            });
        }

        if let Some(description) = embed.description {
            b = b.description(&description);
        }

        if let Some(fields) = embed.fields {
            for field in fields {
                b = b.field(move |f| f
                    .inline(field.inline)
                    .name(&field.name)
                    .value(&field.value));
            }
        }

        if let Some(image) = embed.image {
            b = b.image(move |i| i.url(&image.url));
        }

        if let Some(timestamp) = embed.timestamp {
            b = b.timestamp(&timestamp);
        }

        if let Some(thumbnail) = embed.thumbnail {
            b = b.thumbnail(move |t| t.url(&thumbnail.url));
        }

        if let Some(url) = embed.url {
            b = b.url(&url);
        }

        if let Some(title) = embed.title {
            b = b.title(&title);
        }

        b
    }
}

/// A builder to create a fake [`Embed`] object's author, for use with the
/// [`CreateEmbed::author`] method.
///
/// Requires that you specify a [`name`].
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::author`]: struct.CreateEmbed.html#method.author
/// [`name`]: #method.name
#[derive(Default)]
pub struct CreateEmbedAuthor(pub ObjectBuilder);

impl CreateEmbedAuthor {
    /// Set the URL of the author's icon.
    pub fn icon_url(self, icon_url: &str) -> Self {
        CreateEmbedAuthor(self.0.insert("icon_url", icon_url))
    }

    /// Set the author's name.
    pub fn name(self, name: &str) -> Self {
        CreateEmbedAuthor(self.0.insert("name", name))
    }

    /// Set the author's URL.
    pub fn url(self, url: &str) -> Self {
        CreateEmbedAuthor(self.0.insert("url", url))
    }
}

/// A builder to create a fake [`Embed`] object's field, for use with the
/// [`CreateEmbed::field`] method.
///
/// This does not require any field be set. `inline` is set to `true` by
/// default.
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::field`]: struct.CreateEmbed.html#method.field
pub struct CreateEmbedField(pub ObjectBuilder);

impl CreateEmbedField {
    /// Set whether the field is inlined. Set to true by default.
    pub fn inline(self, inline: bool) -> Self {
        CreateEmbedField(self.0.insert("inline", inline))
    }

    /// Set the field's name. It can't be longer than 256 characters.
    pub fn name(self, name: &str) -> Self {
        CreateEmbedField(self.0.insert("name", name))
    }

    /// Set the field's value. It can't be longer than 1024 characters.
    pub fn value(self, value: &str) -> Self {
        CreateEmbedField(self.0.insert("value", value))
    }
}

impl Default for CreateEmbedField {
    /// Creates a builder with default values, setting the value of `inline` to
    /// `true`.
    fn default() -> CreateEmbedField {
        CreateEmbedField(ObjectBuilder::new().insert("inline", true))
    }
}

/// A builder to create a fake [`Embed`] object's footer, for use with the
/// [`CreateEmbed::footer`] method.
///
/// This does not require any field be set.
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::footer`]: struct.CreateEmbed.html#method.footer
#[derive(Default)]
pub struct CreateEmbedFooter(pub ObjectBuilder);

impl CreateEmbedFooter {
    /// Set the icon URL's value. This only supports HTTP(S).
    pub fn icon_url(self, icon_url: &str) -> Self {
        CreateEmbedFooter(self.0.insert("icon_url", icon_url))
    }

    /// Set the footer's text.
    pub fn text(self, text: &str) -> Self {
        CreateEmbedFooter(self.0.insert("text", text))
    }
}

/// A builder to create a fake [`Embed`] object's image, for use with the
/// [`CreateEmbed::image`] method.
///
/// This does not require any field be set.
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::image`]: struct.CreateEmbed.html#method.image
#[derive(Default)]
pub struct CreateEmbedImage(pub ObjectBuilder);

impl CreateEmbedImage {
    /// Set the display height of the image.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn height(self, height: u64) -> Self {
        CreateEmbedImage(self.0.insert("height", height))
    }

    /// Set the image's URL. This only supports HTTP(S).
    pub fn url(self, url: &str) -> Self {
        CreateEmbedImage(self.0.insert("url", url))
    }

    /// Set the display width of the image.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn width(self, width: u64) -> Self {
        CreateEmbedImage(self.0.insert("width", width))
    }
}

/// A builder to create a fake [`Embed`] object's thumbnail, for use with the
/// [`CreateEmbed::thumbnail`] method.
///
/// Requires that you specify a [`url`].
///
/// [`Embed`]: ../../model/struct.Embed.html
/// [`CreateEmbed::thumbnail`]: struct.CreateEmbed.html#method.thumbnail
/// [`url`]: #method.url
#[derive(Default)]
pub struct CreateEmbedThumbnail(pub ObjectBuilder);

impl CreateEmbedThumbnail {
    /// Set the height of the thumbnail, in pixels.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn height(self, height: u64) -> Self {
        CreateEmbedThumbnail(self.0.insert("height", height))
    }

    /// Set the URL of the thumbnail. This only supports HTTP(S).
    ///
    /// _Must_ be specified.
    pub fn url(self, url: &str) -> Self {
        CreateEmbedThumbnail(self.0.insert("url", url))
    }

    /// Set the width of the thumbnail, in pixels.
    #[deprecated(since="0.1.2", note="Discord does not allow specifying this")]
    pub fn width(self, width: u64) -> Self {
        CreateEmbedThumbnail(self.0.insert("width", width))
    }
}
<|endoftext|>


<commit_before>#![warn(clippy::while_let_loop, clippy::empty_loop, clippy::while_let_on_iterator)]
#![allow(dead_code, clippy::never_loop, unused, clippy::cognitive_complexity)]

fn main() {
    let mut iter = 1..20;
    while let Option::Some(x) = iter.next() {
        println!("{}", x);
    }

    let mut iter = 1..20;
    while let Some(x) = iter.next() {
        println!("{}", x);
    }

    let mut iter = 1..20;
    while let Some(_) = iter.next() {}

    let mut iter = 1..20;
    while let None = iter.next() {} // this is fine (if nonsensical)

    let mut iter = 1..20;
    if let Some(x) = iter.next() {
        // also fine
        println!("{}", x)
    }

    // the following shouldn't warn because it can't be written with a for loop
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        println!("next: {:?}", iter.next())
    }

    // neither can this
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        println!("next: {:?}", iter.next());
    }

    // or this
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        break;
    }
    println!("Remaining iter {:?}", iter);

    // or this
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        iter = 1..20;
    }
}

// Issue #1188
fn refutable() {
    let a = [42, 1337];
    let mut b = a.iter();

    // consume all the 42s
    while let Some(&42) = b.next() {}

    let a = [(1, 2, 3)];
    let mut b = a.iter();

    while let Some(&(1, 2, 3)) = b.next() {}

    let a = [Some(42)];
    let mut b = a.iter();

    while let Some(&None) = b.next() {}

    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
    for &42 in b {}
    for &(1, 2, 3) in b {}
    for &Option::None in b.next() {}
    // */
}

fn nested_loops() {
    let a = [42, 1337];
    let mut y = a.iter();
    loop {
        // x is reused, so don't lint here
        while let Some(v) = y.next() {}
    }

    let mut y = a.iter();
    for _ in 0..2 {
        while let Some(v) = y.next() {
            // y is reused, don't lint
        }
    }

    loop {
        let mut y = a.iter();
        while let Some(v) = y.next() {
            // use a for loop here
        }
    }
}

fn issue1121() {
    use std::collections::HashSet;
    let mut values = HashSet::new();
    values.insert(1);

    while let Some(&value) = values.iter().next() {
        values.remove(&value);
    }
}

fn issue2965() {
    // This should not cause an ICE and suggest:
    //
    // for _ in values.iter() {}
    //
    use std::collections::HashSet;
    let mut values = HashSet::new();
    values.insert(1);

    while let Some(..) = values.iter().next() {
        values.remove(&1);
    }
}

fn issue3670() {
    let array = [Some(0), None, Some(1)];
    let mut iter = array.iter();

    while let Some(elem) = iter.next() {
        let _ = elem.or_else(|| *iter.next()?);
    }
}
<commit_msg>Remove unused attrs in while_let_on_iterator tests<commit_after>#![warn(clippy::while_let_on_iterator)]
#![allow(clippy::never_loop, clippy::cognitive_complexity)]

fn main() {
    let mut iter = 1..20;
    while let Option::Some(x) = iter.next() {
        println!("{}", x);
    }

    let mut iter = 1..20;
    while let Some(x) = iter.next() {
        println!("{}", x);
    }

    let mut iter = 1..20;
    while let Some(_) = iter.next() {}

    let mut iter = 1..20;
    while let None = iter.next() {} // this is fine (if nonsensical)

    let mut iter = 1..20;
    if let Some(x) = iter.next() {
        // also fine
        println!("{}", x)
    }

    // the following shouldn't warn because it can't be written with a for loop
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        println!("next: {:?}", iter.next())
    }

    // neither can this
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        println!("next: {:?}", iter.next());
    }

    // or this
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        break;
    }
    println!("Remaining iter {:?}", iter);

    // or this
    let mut iter = 1u32..20;
    while let Some(x) = iter.next() {
        iter = 1..20;
    }
}

// Issue #1188
fn refutable() {
    let a = [42, 1337];
    let mut b = a.iter();

    // consume all the 42s
    while let Some(&42) = b.next() {}

    let a = [(1, 2, 3)];
    let mut b = a.iter();

    while let Some(&(1, 2, 3)) = b.next() {}

    let a = [Some(42)];
    let mut b = a.iter();

    while let Some(&None) = b.next() {}

    /* This gives “refutable pattern in `for` loop binding: `&_` not covered”
    for &42 in b {}
    for &(1, 2, 3) in b {}
    for &Option::None in b.next() {}
    // */
}

fn nested_loops() {
    let a = [42, 1337];
    let mut y = a.iter();
    loop {
        // x is reused, so don't lint here
        while let Some(v) = y.next() {}
    }

    let mut y = a.iter();
    for _ in 0..2 {
        while let Some(v) = y.next() {
            // y is reused, don't lint
        }
    }

    loop {
        let mut y = a.iter();
        while let Some(v) = y.next() {
            // use a for loop here
        }
    }
}

fn issue1121() {
    use std::collections::HashSet;
    let mut values = HashSet::new();
    values.insert(1);

    while let Some(&value) = values.iter().next() {
        values.remove(&value);
    }
}

fn issue2965() {
    // This should not cause an ICE and suggest:
    //
    // for _ in values.iter() {}
    //
    use std::collections::HashSet;
    let mut values = HashSet::new();
    values.insert(1);

    while let Some(..) = values.iter().next() {
        values.remove(&1);
    }
}

fn issue3670() {
    let array = [Some(0), None, Some(1)];
    let mut iter = array.iter();

    while let Some(elem) = iter.next() {
        let _ = elem.or_else(|| *iter.next()?);
    }
}
<|endoftext|>


<commit_before>extern crate log;
extern crate libc;
extern crate mach;

pub use self::iokit::*;
mod iokit;
mod iohid;

use rand::{thread_rng, Rng};
use std::fmt;
use std::io::{Read, Write};
use std::io;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use libc::c_void;

use mach::kern_return::KERN_SUCCESS;

use core_foundation_sys::base::*;

mod monitor;
use self::monitor::Monitor;
use std::collections::HashMap;
use runloop::RunLoop;

use consts::{CID_BROADCAST, HID_RPT_SIZE, PARAMETER_SIZE};
use U2FDevice;

const READ_TIMEOUT: u64 = 15;

pub struct Report {
    pub data: [u8; HID_RPT_SIZE],
}
unsafe impl Send for Report {}
unsafe impl Sync for Report {}

pub struct Device {
    pub device_ref: IOHIDDeviceRef,
    // Channel ID for U2F HID communication. Needed to implement U2FDevice
    // trait.
    pub cid: [u8; 4],
    pub report_recv: Receiver<Report>,
    pub report_send_void: *mut libc::c_void,
}

impl fmt::Display for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "InternalDevice(ref:{:?}, cid: {:02x}{:02x}{:02x}{:02x})",
               self.device_ref, self.cid[0], self.cid[1], self.cid[2], self.cid[3])
    }
}

impl PartialEq for Device {
    fn eq(&self, other_device: &Device) -> bool {
        self.device_ref == other_device.device_ref
    }
}

impl Read for Device {
    fn read(&mut self, mut bytes: &mut [u8]) -> io::Result<usize> {
        let timeout = Duration::from_secs(READ_TIMEOUT);
        let report_data = match self.report_recv.recv_timeout(timeout) {
            Ok(v) => v,
            Err(e) => {
                if e == RecvTimeoutError::Timeout {
                    return Err(io::Error::new(io::ErrorKind::TimedOut, e));
                }
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, e));
            },
        };
        let len = bytes.write(&report_data.data).unwrap();
        Ok(len)
    }
}

impl Write for Device {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        unsafe { set_report(self.device_ref, kIOHIDReportTypeOutput, bytes) }
    }

    // USB HID writes don't buffer, so this will be a nop.
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl U2FDevice for Device {
    fn get_cid(&self) -> [u8; 4] {
        return self.cid.clone();
    }
    fn set_cid(&mut self, cid: &[u8; 4]) {
        self.cid.clone_from(cid);
    }
}

pub struct PlatformManager {
  // Handle to the thread loop.
  thread: Option<RunLoop>
}

impl PlatformManager {
    pub fn new() -> Self {
        Self { thread: None }
    }

    // Non-blocking
    pub fn register<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, None, callback)
    }

    // Non-blocking
    pub fn sign<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, Some(key_handle), callback)
    }

    // Can block
    pub fn cancel(&mut self) {
        if let Some(mut thread) = self.thread.take() {
            thread.cancel();
        }
    }

    fn run_thread<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Option<Vec<u8>>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        // Abort any prior register/sign calls.
        self.cancel();

        self.thread = Some(RunLoop::new(move |alive| {
            let mut monitor = Monitor::new()?;
            let mut devices = HashMap::new();

            // Helper to stop monitor and call back.
            let complete = |monitor: &mut Monitor, rv| {
                monitor.stop();
                callback(rv);
                Ok(())
            };

            'top: while alive() {
                for event in monitor.events() {
                    process_event(&mut devices, event);
                }

                for device in devices.values_mut() {
                    // Check to see if monitor.events has any hotplug events that we'll need to handle
                    if monitor.events().size_hint().0 > 0 {
                        debug!("Hotplug event; restarting loop");
                        continue 'top;
                    }

                    if let Some(ref key) = key_handle {
                        // Determine if this key handle belongs to this token
                        let is_valid = match super::u2f_is_keyhandle_valid(device, &challenge, &application, key) {
                            Err(_) => continue,
                            Ok(result) => result,
                        };

                        if is_valid {
                            // It does, we can sign
                            if let Ok(bytes) = super::u2f_sign(device, &challenge, &application, key) {
                                return complete(&mut monitor, Ok(bytes));
                            }
                        } else {
                            // If doesn't, so blink anyway (using bogus data)
                            let blank = vec![0u8; PARAMETER_SIZE];

                            if let Ok(_) = super::u2f_register(device, &blank, &blank) {
                                // If the user selects this token that can't satisfy, it's an error
                                return complete(&mut monitor, Err(io::Error::new(io::ErrorKind::ConnectionRefused, "User chose invalid key")));
                            }
                        }
                    } else {
                        // Caller asked us to register, so the first token that does wins
                        if let Ok(bytes) = super::u2f_register(device, &challenge, &application) {
                            return complete(&mut monitor, Ok(bytes));
                        }
                    }
                }

                thread::sleep(Duration::from_millis(100));
            }

            complete(&mut monitor, Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")))
        }, timeout)?);

        Ok(())
    }
}

fn maybe_add_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    if devs.contains_key(&device_ref) {
        return;
    }

    let scratch_buf = [0; HID_RPT_SIZE];
    let (report_tx, report_rx) = channel::<Report>();

    let boxed_report_tx = Box::new(report_tx);
    // report_tx_ptr is deallocated by maybe_remove_device
    let report_tx_ptr = Box::into_raw(boxed_report_tx) as *mut libc::c_void;

    let mut dev = Device {
        device_ref: device_ref,
        cid: CID_BROADCAST,
        report_recv: report_rx,
        report_send_void: report_tx_ptr,
    };

    unsafe { IOHIDDeviceRegisterInputReportCallback(device_ref,
                                                    scratch_buf.as_ptr(),
                                                    scratch_buf.len() as CFIndex,
                                                    read_new_data_cb,
                                                    report_tx_ptr) };

    let mut nonce = [0u8; 8];
    thread_rng().fill_bytes(&mut nonce);
    if let Err(_) = super::init_device(&mut dev, nonce) {
        return;
    }

    let mut random = [0u8; 8];
    thread_rng().fill_bytes(&mut random);
    if let Err(_) = super::ping_device(&mut dev, random) {
        return;
    }
    if let Err(_) = super::u2f_version_is_v2(&mut dev) {
        return;
    }

    debug!("added U2F device {}", dev);
    devs.insert(device_ref, dev);
}

fn maybe_remove_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    match devs.remove(&device_ref) {
        Some(dev) => {
            debug!("removing U2F device {}", dev);
            // Re-allocate this raw pointer for destruction
            let _ = unsafe { Box::from_raw(dev.report_send_void) };
        },
        None => { warn!("Couldn't remove {:?}", device_ref); },
    }
}

fn process_event(devs: &mut HashMap<IOHIDDeviceRef, Device>, event: monitor::Event) {
    match event {
        monitor::Event::Add { device_id } => maybe_add_device(devs, device_id.as_ref()),
        monitor::Event::Remove { device_id } => maybe_remove_device(devs, device_id.as_ref()),
    }
}

unsafe fn set_report(device_ref: IOHIDDeviceRef,
                     report_type: IOHIDReportType,
                     bytes: &[u8])
                     -> io::Result<usize> {
    let report_id = bytes[0] as i64;
    let mut data = bytes.as_ptr();
    let mut length = bytes.len() as CFIndex;

    if report_id == 0x0 {
        // Not using numbered reports, so don't send the report number
        length = length - 1;
        data = data.offset(1);
    }

    let result = IOHIDDeviceSetReport(device_ref, report_type, report_id, data, length);
    if result != KERN_SUCCESS {
        warn!("set_report sending failure = {0:X}", result);

        return Err(io::Error::from_raw_os_error(result));
    }
    trace!("set_report sending success = {0:X}", result);

    Ok(length as usize)
}

// This is called from the RunLoop thread
extern "C" fn read_new_data_cb(context: *mut c_void,
                               _: IOReturn,
                               _: *mut c_void,
                               report_type: IOHIDReportType,
                               report_id: u32,
                               report: *mut u8,
                               report_len: CFIndex) {
    unsafe {
        let tx: &mut Sender<Report> = &mut *(context as *mut Sender<Report>);

        trace!("read_new_data_cb type={} id={} report={:?} len={}",
                 report_type,
                 report_id,
                 report,
                 report_len);

        let mut report_obj = Report { data: [0; HID_RPT_SIZE] };

        if report_len as usize <= HID_RPT_SIZE {
            ptr::copy(report, report_obj.data.as_mut_ptr(), report_len as usize);
        } else {
            warn!("read_new_data_cb got too much data! {} > {}",
                     report_len,
                     HID_RPT_SIZE);
        }

        if let Err(e) = tx.send(report_obj) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            warn!("Problem returning read_new_data_cb data for thread: {}", e);
        };
    }
}

<commit_msg>Move the OSX hotplug check to be on the tail end of the device loop<commit_after>extern crate log;
extern crate libc;
extern crate mach;

pub use self::iokit::*;
mod iokit;
mod iohid;

use rand::{thread_rng, Rng};
use std::fmt;
use std::io::{Read, Write};
use std::io;
use std::ptr;
use std::sync::mpsc::{channel, Sender, Receiver, RecvTimeoutError};
use std::thread;
use std::time::Duration;

use libc::c_void;

use mach::kern_return::KERN_SUCCESS;

use core_foundation_sys::base::*;

mod monitor;
use self::monitor::Monitor;
use std::collections::HashMap;
use runloop::RunLoop;

use consts::{CID_BROADCAST, HID_RPT_SIZE, PARAMETER_SIZE};
use U2FDevice;

const READ_TIMEOUT: u64 = 15;

pub struct Report {
    pub data: [u8; HID_RPT_SIZE],
}
unsafe impl Send for Report {}
unsafe impl Sync for Report {}

pub struct Device {
    pub device_ref: IOHIDDeviceRef,
    // Channel ID for U2F HID communication. Needed to implement U2FDevice
    // trait.
    pub cid: [u8; 4],
    pub report_recv: Receiver<Report>,
    pub report_send_void: *mut libc::c_void,
}

impl fmt::Display for Device {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "InternalDevice(ref:{:?}, cid: {:02x}{:02x}{:02x}{:02x})",
               self.device_ref, self.cid[0], self.cid[1], self.cid[2], self.cid[3])
    }
}

impl PartialEq for Device {
    fn eq(&self, other_device: &Device) -> bool {
        self.device_ref == other_device.device_ref
    }
}

impl Read for Device {
    fn read(&mut self, mut bytes: &mut [u8]) -> io::Result<usize> {
        let timeout = Duration::from_secs(READ_TIMEOUT);
        let report_data = match self.report_recv.recv_timeout(timeout) {
            Ok(v) => v,
            Err(e) => {
                if e == RecvTimeoutError::Timeout {
                    return Err(io::Error::new(io::ErrorKind::TimedOut, e));
                }
                return Err(io::Error::new(io::ErrorKind::UnexpectedEof, e));
            },
        };
        let len = bytes.write(&report_data.data).unwrap();
        Ok(len)
    }
}

impl Write for Device {
    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
        unsafe { set_report(self.device_ref, kIOHIDReportTypeOutput, bytes) }
    }

    // USB HID writes don't buffer, so this will be a nop.
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl U2FDevice for Device {
    fn get_cid(&self) -> [u8; 4] {
        return self.cid.clone();
    }
    fn set_cid(&mut self, cid: &[u8; 4]) {
        self.cid.clone_from(cid);
    }
}

pub struct PlatformManager {
  // Handle to the thread loop.
  thread: Option<RunLoop>
}

impl PlatformManager {
    pub fn new() -> Self {
        Self { thread: None }
    }

    // Non-blocking
    pub fn register<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, None, callback)
    }

    // Non-blocking
    pub fn sign<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Vec<u8>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        self.run_thread(timeout, challenge, application, Some(key_handle), callback)
    }

    // Can block
    pub fn cancel(&mut self) {
        if let Some(mut thread) = self.thread.take() {
            thread.cancel();
        }
    }

    fn run_thread<F>(&mut self, timeout: u64, challenge: Vec<u8>, application: Vec<u8>, key_handle: Option<Vec<u8>>, callback: F) -> io::Result<()>
        where F: FnOnce(io::Result<Vec<u8>>), F: Send + 'static
    {
        // Abort any prior register/sign calls.
        self.cancel();

        self.thread = Some(RunLoop::new(move |alive| {
            let mut monitor = Monitor::new()?;
            let mut devices = HashMap::new();

            // Helper to stop monitor and call back.
            let complete = |monitor: &mut Monitor, rv| {
                monitor.stop();
                callback(rv);
                Ok(())
            };

            'top: while alive() {
                for event in monitor.events() {
                    process_event(&mut devices, event);
                }

                for device in devices.values_mut() {
                    if let Some(ref key) = key_handle {
                        // Determine if this key handle belongs to this token
                        let is_valid = match super::u2f_is_keyhandle_valid(device, &challenge, &application, key) {
                            Err(_) => continue,
                            Ok(result) => result,
                        };

                        if is_valid {
                            // It does, we can sign
                            if let Ok(bytes) = super::u2f_sign(device, &challenge, &application, key) {
                                return complete(&mut monitor, Ok(bytes));
                            }
                        } else {
                            // If doesn't, so blink anyway (using bogus data)
                            let blank = vec![0u8; PARAMETER_SIZE];

                            if let Ok(_) = super::u2f_register(device, &blank, &blank) {
                                // If the user selects this token that can't satisfy, it's an error
                                return complete(&mut monitor, Err(io::Error::new(io::ErrorKind::ConnectionRefused, "User chose invalid key")));
                            }
                        }
                    } else {
                        // Caller asked us to register, so the first token that does wins
                        if let Ok(bytes) = super::u2f_register(device, &challenge, &application) {
                            return complete(&mut monitor, Ok(bytes));
                        }
                    }

                    // Check to see if monitor.events has any hotplug events that we'll need to handle
                    if monitor.events().size_hint().0 > 0 {
                        debug!("Hotplug event; restarting loop");
                        continue 'top;
                    }
                }

                thread::sleep(Duration::from_millis(100));
            }

            complete(&mut monitor, Err(io::Error::new(io::ErrorKind::TimedOut, "Timed out")))
        }, timeout)?);

        Ok(())
    }
}

fn maybe_add_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    if devs.contains_key(&device_ref) {
        return;
    }

    let scratch_buf = [0; HID_RPT_SIZE];
    let (report_tx, report_rx) = channel::<Report>();

    let boxed_report_tx = Box::new(report_tx);
    // report_tx_ptr is deallocated by maybe_remove_device
    let report_tx_ptr = Box::into_raw(boxed_report_tx) as *mut libc::c_void;

    let mut dev = Device {
        device_ref: device_ref,
        cid: CID_BROADCAST,
        report_recv: report_rx,
        report_send_void: report_tx_ptr,
    };

    unsafe { IOHIDDeviceRegisterInputReportCallback(device_ref,
                                                    scratch_buf.as_ptr(),
                                                    scratch_buf.len() as CFIndex,
                                                    read_new_data_cb,
                                                    report_tx_ptr) };

    let mut nonce = [0u8; 8];
    thread_rng().fill_bytes(&mut nonce);
    if let Err(_) = super::init_device(&mut dev, nonce) {
        return;
    }

    let mut random = [0u8; 8];
    thread_rng().fill_bytes(&mut random);
    if let Err(_) = super::ping_device(&mut dev, random) {
        return;
    }
    if let Err(_) = super::u2f_version_is_v2(&mut dev) {
        return;
    }

    debug!("added U2F device {}", dev);
    devs.insert(device_ref, dev);
}

fn maybe_remove_device(devs: &mut HashMap<IOHIDDeviceRef, Device>, device_ref: IOHIDDeviceRef) {
    match devs.remove(&device_ref) {
        Some(dev) => {
            debug!("removing U2F device {}", dev);
            // Re-allocate this raw pointer for destruction
            let _ = unsafe { Box::from_raw(dev.report_send_void) };
        },
        None => { warn!("Couldn't remove {:?}", device_ref); },
    }
}

fn process_event(devs: &mut HashMap<IOHIDDeviceRef, Device>, event: monitor::Event) {
    match event {
        monitor::Event::Add { device_id } => maybe_add_device(devs, device_id.as_ref()),
        monitor::Event::Remove { device_id } => maybe_remove_device(devs, device_id.as_ref()),
    }
}

unsafe fn set_report(device_ref: IOHIDDeviceRef,
                     report_type: IOHIDReportType,
                     bytes: &[u8])
                     -> io::Result<usize> {
    let report_id = bytes[0] as i64;
    let mut data = bytes.as_ptr();
    let mut length = bytes.len() as CFIndex;

    if report_id == 0x0 {
        // Not using numbered reports, so don't send the report number
        length = length - 1;
        data = data.offset(1);
    }

    let result = IOHIDDeviceSetReport(device_ref, report_type, report_id, data, length);
    if result != KERN_SUCCESS {
        warn!("set_report sending failure = {0:X}", result);

        return Err(io::Error::from_raw_os_error(result));
    }
    trace!("set_report sending success = {0:X}", result);

    Ok(length as usize)
}

// This is called from the RunLoop thread
extern "C" fn read_new_data_cb(context: *mut c_void,
                               _: IOReturn,
                               _: *mut c_void,
                               report_type: IOHIDReportType,
                               report_id: u32,
                               report: *mut u8,
                               report_len: CFIndex) {
    unsafe {
        let tx: &mut Sender<Report> = &mut *(context as *mut Sender<Report>);

        trace!("read_new_data_cb type={} id={} report={:?} len={}",
                 report_type,
                 report_id,
                 report,
                 report_len);

        let mut report_obj = Report { data: [0; HID_RPT_SIZE] };

        if report_len as usize <= HID_RPT_SIZE {
            ptr::copy(report, report_obj.data.as_mut_ptr(), report_len as usize);
        } else {
            warn!("read_new_data_cb got too much data! {} > {}",
                     report_len,
                     HID_RPT_SIZE);
        }

        if let Err(e) = tx.send(report_obj) {
            // TOOD: This happens when the channel closes before this thread
            // does. This is pretty common, but let's deal with stopping
            // properly later.
            warn!("Problem returning read_new_data_cb data for thread: {}", e);
        };
    }
}

<|endoftext|>


<commit_before>use hir::{HasSource, HirDisplay, InFile};
use ide_db::assists::{AssistId, AssistKind};
use syntax::{
    ast::{self, make, HasArgList},
    AstNode,
};

use crate::assist_context::{AssistContext, Assists};

// Assist: generate_enum_variant
//
// Adds a variant to an enum.
//
// ```
// enum Countries {
//     Ghana,
// }
//
// fn main() {
//     let country = Countries::Lesotho$0;
// }
// ```
// ->
// ```
// enum Countries {
//     Ghana,
//     Lesotho,
// }
//
// fn main() {
//     let country = Countries::Lesotho;
// }
// ```
pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let path: ast::Path = ctx.find_node_at_offset()?;

    if ctx.sema.resolve_path(&path).is_some() {
        // No need to generate anything if the path resolves
        return None;
    }

    let name_ref = path.segment()?.name_ref()?;
    if name_ref.text().starts_with(char::is_lowercase) {
        // Don't suggest generating variant if the name starts with a lowercase letter
        return None;
    }

    if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e)))) =
        ctx.sema.resolve_path(&path.qualifier()?)
    {
        let target = path.syntax().text_range();
        return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, &path);
    }

    None
}

fn add_variant_to_accumulator(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
    target: syntax::TextRange,
    adt: hir::Enum,
    name_ref: &ast::NameRef,
    path: &ast::Path,
) -> Option<()> {
    let db = ctx.db();
    let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?;

    acc.add(
        AssistId("generate_enum_variant", AssistKind::Generate),
        "Generate variant",
        target,
        |builder| {
            builder.edit_file(file_id.original_file(db));
            let node = builder.make_mut(enum_node);
            let variant = make_variant(ctx, name_ref, &path);
            node.variant_list().map(|it| it.add_variant(variant.clone_for_update()));
        },
    )
}

fn make_variant(
    ctx: &AssistContext<'_>,
    name_ref: &ast::NameRef,
    path: &ast::Path,
) -> ast::Variant {
    let field_list = make_field_list(ctx, path);
    make::variant(make::name(&name_ref.text()), field_list)
}

fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option<ast::FieldList> {
    let scope = ctx.sema.scope(&path.syntax())?;
    if let Some(call_expr) =
        path.syntax().parent().and_then(|it| it.parent()).and_then(ast::CallExpr::cast)
    {
        make_tuple_field_list(call_expr, ctx, &scope)
    } else if let Some(record_expr) = path.syntax().parent().and_then(ast::RecordExpr::cast) {
        make_record_field_list(record_expr, ctx, &scope)
    } else {
        None
    }
}

fn make_record_field_list(
    record: ast::RecordExpr,
    ctx: &AssistContext<'_>,
    scope: &hir::SemanticsScope<'_>,
) -> Option<ast::FieldList> {
    let fields = record.record_expr_field_list()?.fields();
    let record_fields = fields.map(|field| {
        let name = name_from_field(&field);

        let ty = field
            .expr()
            .and_then(|it| expr_ty(ctx, it, scope))
            .unwrap_or_else(make::ty_placeholder);

        make::record_field(None, name, ty)
    });
    Some(make::record_field_list(record_fields).into())
}

fn name_from_field(field: &ast::RecordExprField) -> ast::Name {
    let text = match field.name_ref() {
        Some(it) => it.to_string(),
        None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()),
    };
    make::name(&text)
}

fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option<String> {
    let path = match field.expr()? {
        ast::Expr::PathExpr(path_expr) => path_expr.path(),
        _ => None,
    }?;
    Some(path.as_single_name_ref()?.to_string())
}

fn make_tuple_field_list(
    call_expr: ast::CallExpr,
    ctx: &AssistContext<'_>,
    scope: &hir::SemanticsScope<'_>,
) -> Option<ast::FieldList> {
    let args = call_expr.arg_list()?.args();
    let tuple_fields = args.map(|arg| {
        let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder);
        make::tuple_field(None, ty)
    });
    Some(make::tuple_field_list(tuple_fields).into())
}

fn expr_ty(
    ctx: &AssistContext<'_>,
    arg: ast::Expr,
    scope: &hir::SemanticsScope<'_>,
) -> Option<ast::Type> {
    let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?;
    let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?;
    Some(make::ty(&text))
}

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

    use super::*;

    #[test]
    fn generate_basic_enum_variant_in_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0
}
",
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_non_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Baz$0
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
fn main() {
    Foo::Baz
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_different_file() {
        check_assist(
            generate_enum_variant,
            r"
//- /main.rs
mod foo;
use foo::Foo;

fn main() {
    Foo::Baz$0
}

//- /foo.rs
enum Foo {
    Bar,
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
",
        )
    }

    #[test]
    fn not_applicable_for_existing_variant() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar$0
}
",
        )
    }

    #[test]
    fn not_applicable_for_lowercase() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::new$0
}
",
        )
    }

    #[test]
    fn indentation_level_is_correct() {
        check_assist(
            generate_enum_variant,
            r"
mod m {
    enum Foo {
        Bar,
    }
}
fn main() {
    m::Foo::Baz$0
}
",
            r"
mod m {
    enum Foo {
        Bar,
        Baz,
    }
}
fn main() {
    m::Foo::Baz
}
",
        )
    }

    #[test]
    fn associated_single_element_tuple() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0(true)
}
",
            r"
enum Foo {
    Bar(bool),
}
fn main() {
    Foo::Bar(true)
}
",
        )
    }

    #[test]
    fn associated_single_element_tuple_unknown_type() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0(x)
}
",
            r"
enum Foo {
    Bar(_),
}
fn main() {
    Foo::Bar(x)
}
",
        )
    }

    #[test]
    fn associated_multi_element_tuple() {
        check_assist(
            generate_enum_variant,
            r"
struct Struct {}
enum Foo {}
fn main() {
    Foo::Bar$0(true, x, Struct {})
}
",
            r"
struct Struct {}
enum Foo {
    Bar(bool, _, Struct),
}
fn main() {
    Foo::Bar(true, x, Struct {})
}
",
        )
    }

    #[test]
    fn associated_record() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::$0Bar { x: true }
}
",
            r"
enum Foo {
    Bar { x: bool },
}
fn main() {
    Foo::Bar { x: true }
}
",
        )
    }

    #[test]
    fn associated_record_unknown_type() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::$0Bar { x: y }
}
",
            r"
enum Foo {
    Bar { x: _ },
}
fn main() {
    Foo::Bar { x: y }
}
",
        )
    }

    #[test]
    fn associated_record_field_shorthand() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    let x = true;
    Foo::$0Bar { x }
}
",
            r"
enum Foo {
    Bar { x: bool },
}
fn main() {
    let x = true;
    Foo::Bar { x }
}
",
        )
    }

    #[test]
    fn associated_record_field_shorthand_unknown_type() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::$0Bar { x }
}
",
            r"
enum Foo {
    Bar { x: _ },
}
fn main() {
    Foo::Bar { x }
}
",
        )
    }

    #[test]
    fn associated_record_field_multiple_fields() {
        check_assist(
            generate_enum_variant,
            r"
struct Struct {}
enum Foo {}
fn main() {
    Foo::$0Bar { x, y: x, s: Struct {} }
}
",
            r"
struct Struct {}
enum Foo {
    Bar { x: _, y: _, s: Struct },
}
fn main() {
    Foo::Bar { x, y: x, s: Struct {} }
}
",
        )
    }
}
<commit_msg>Be more strict about supported Paths in generate_enum_variant<commit_after>use hir::{HasSource, HirDisplay, InFile};
use ide_db::assists::{AssistId, AssistKind};
use syntax::{
    ast::{self, make, HasArgList},
    match_ast, AstNode, SyntaxNode,
};

use crate::assist_context::{AssistContext, Assists};

// Assist: generate_enum_variant
//
// Adds a variant to an enum.
//
// ```
// enum Countries {
//     Ghana,
// }
//
// fn main() {
//     let country = Countries::Lesotho$0;
// }
// ```
// ->
// ```
// enum Countries {
//     Ghana,
//     Lesotho,
// }
//
// fn main() {
//     let country = Countries::Lesotho;
// }
// ```
pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
    let path: ast::Path = ctx.find_node_at_offset()?;
    let parent = path_parent(&path)?;

    if ctx.sema.resolve_path(&path).is_some() {
        // No need to generate anything if the path resolves
        return None;
    }

    let name_ref = path.segment()?.name_ref()?;
    if name_ref.text().starts_with(char::is_lowercase) {
        // Don't suggest generating variant if the name starts with a lowercase letter
        return None;
    }

    if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e)))) =
        ctx.sema.resolve_path(&path.qualifier()?)
    {
        let target = path.syntax().text_range();
        return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent);
    }

    None
}

#[derive(Debug)]
enum PathParent {
    PathExpr(ast::PathExpr),
    RecordExpr(ast::RecordExpr),
    UseTree(ast::UseTree),
}

impl PathParent {
    fn syntax(&self) -> &SyntaxNode {
        match self {
            PathParent::PathExpr(it) => it.syntax(),
            PathParent::RecordExpr(it) => it.syntax(),
            PathParent::UseTree(it) => it.syntax(),
        }
    }

    fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option<ast::FieldList> {
        let scope = ctx.sema.scope(self.syntax())?;

        match self {
            PathParent::PathExpr(it) => {
                if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) {
                    make_tuple_field_list(call_expr, ctx, &scope)
                } else {
                    None
                }
            }
            PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope),
            PathParent::UseTree(_) => None,
        }
    }
}

fn path_parent(path: &ast::Path) -> Option<PathParent> {
    let parent = path.syntax().parent()?;

    match_ast! {
        match parent {
            ast::PathExpr(it) => Some(PathParent::PathExpr(it)),
            ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)),
            ast::UseTree(it) => Some(PathParent::UseTree(it)),
            _ => None
        }
    }
}

fn add_variant_to_accumulator(
    acc: &mut Assists,
    ctx: &AssistContext<'_>,
    target: syntax::TextRange,
    adt: hir::Enum,
    name_ref: &ast::NameRef,
    parent: PathParent,
) -> Option<()> {
    let db = ctx.db();
    let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?;

    acc.add(
        AssistId("generate_enum_variant", AssistKind::Generate),
        "Generate variant",
        target,
        |builder| {
            builder.edit_file(file_id.original_file(db));
            let node = builder.make_mut(enum_node);
            let variant = make_variant(ctx, name_ref, parent);
            node.variant_list().map(|it| it.add_variant(variant.clone_for_update()));
        },
    )
}

fn make_variant(
    ctx: &AssistContext<'_>,
    name_ref: &ast::NameRef,
    parent: PathParent,
) -> ast::Variant {
    let field_list = parent.make_field_list(ctx);
    make::variant(make::name(&name_ref.text()), field_list)
}

fn make_record_field_list(
    record: &ast::RecordExpr,
    ctx: &AssistContext<'_>,
    scope: &hir::SemanticsScope<'_>,
) -> Option<ast::FieldList> {
    let fields = record.record_expr_field_list()?.fields();
    let record_fields = fields.map(|field| {
        let name = name_from_field(&field);

        let ty = field
            .expr()
            .and_then(|it| expr_ty(ctx, it, scope))
            .unwrap_or_else(make::ty_placeholder);

        make::record_field(None, name, ty)
    });
    Some(make::record_field_list(record_fields).into())
}

fn name_from_field(field: &ast::RecordExprField) -> ast::Name {
    let text = match field.name_ref() {
        Some(it) => it.to_string(),
        None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()),
    };
    make::name(&text)
}

fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option<String> {
    let path = match field.expr()? {
        ast::Expr::PathExpr(path_expr) => path_expr.path(),
        _ => None,
    }?;
    Some(path.as_single_name_ref()?.to_string())
}

fn make_tuple_field_list(
    call_expr: ast::CallExpr,
    ctx: &AssistContext<'_>,
    scope: &hir::SemanticsScope<'_>,
) -> Option<ast::FieldList> {
    let args = call_expr.arg_list()?.args();
    let tuple_fields = args.map(|arg| {
        let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder);
        make::tuple_field(None, ty)
    });
    Some(make::tuple_field_list(tuple_fields).into())
}

fn expr_ty(
    ctx: &AssistContext<'_>,
    arg: ast::Expr,
    scope: &hir::SemanticsScope<'_>,
) -> Option<ast::Type> {
    let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?;
    let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?;
    Some(make::ty(&text))
}

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

    use super::*;

    #[test]
    fn generate_basic_enum_variant_in_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0
}
",
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_non_empty_enum() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Baz$0
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
fn main() {
    Foo::Baz
}
",
        )
    }

    #[test]
    fn generate_basic_enum_variant_in_different_file() {
        check_assist(
            generate_enum_variant,
            r"
//- /main.rs
mod foo;
use foo::Foo;

fn main() {
    Foo::Baz$0
}

//- /foo.rs
enum Foo {
    Bar,
}
",
            r"
enum Foo {
    Bar,
    Baz,
}
",
        )
    }

    #[test]
    fn not_applicable_for_existing_variant() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::Bar$0
}
",
        )
    }

    #[test]
    fn not_applicable_for_lowercase() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {
    Bar,
}
fn main() {
    Foo::new$0
}
",
        )
    }

    #[test]
    fn indentation_level_is_correct() {
        check_assist(
            generate_enum_variant,
            r"
mod m {
    enum Foo {
        Bar,
    }
}
fn main() {
    m::Foo::Baz$0
}
",
            r"
mod m {
    enum Foo {
        Bar,
        Baz,
    }
}
fn main() {
    m::Foo::Baz
}
",
        )
    }

    #[test]
    fn associated_single_element_tuple() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0(true)
}
",
            r"
enum Foo {
    Bar(bool),
}
fn main() {
    Foo::Bar(true)
}
",
        )
    }

    #[test]
    fn associated_single_element_tuple_unknown_type() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::Bar$0(x)
}
",
            r"
enum Foo {
    Bar(_),
}
fn main() {
    Foo::Bar(x)
}
",
        )
    }

    #[test]
    fn associated_multi_element_tuple() {
        check_assist(
            generate_enum_variant,
            r"
struct Struct {}
enum Foo {}
fn main() {
    Foo::Bar$0(true, x, Struct {})
}
",
            r"
struct Struct {}
enum Foo {
    Bar(bool, _, Struct),
}
fn main() {
    Foo::Bar(true, x, Struct {})
}
",
        )
    }

    #[test]
    fn associated_record() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::$0Bar { x: true }
}
",
            r"
enum Foo {
    Bar { x: bool },
}
fn main() {
    Foo::Bar { x: true }
}
",
        )
    }

    #[test]
    fn associated_record_unknown_type() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::$0Bar { x: y }
}
",
            r"
enum Foo {
    Bar { x: _ },
}
fn main() {
    Foo::Bar { x: y }
}
",
        )
    }

    #[test]
    fn associated_record_field_shorthand() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    let x = true;
    Foo::$0Bar { x }
}
",
            r"
enum Foo {
    Bar { x: bool },
}
fn main() {
    let x = true;
    Foo::Bar { x }
}
",
        )
    }

    #[test]
    fn associated_record_field_shorthand_unknown_type() {
        check_assist(
            generate_enum_variant,
            r"
enum Foo {}
fn main() {
    Foo::$0Bar { x }
}
",
            r"
enum Foo {
    Bar { x: _ },
}
fn main() {
    Foo::Bar { x }
}
",
        )
    }

    #[test]
    fn associated_record_field_multiple_fields() {
        check_assist(
            generate_enum_variant,
            r"
struct Struct {}
enum Foo {}
fn main() {
    Foo::$0Bar { x, y: x, s: Struct {} }
}
",
            r"
struct Struct {}
enum Foo {
    Bar { x: _, y: _, s: Struct },
}
fn main() {
    Foo::Bar { x, y: x, s: Struct {} }
}
",
        )
    }

    #[test]
    fn use_tree() {
        check_assist(
            generate_enum_variant,
            r"
//- /main.rs
mod foo;
use foo::Foo::Bar$0;

//- /foo.rs
enum Foo {}
",
            r"
enum Foo {
    Bar,
}
",
        )
    }

    #[test]
    fn not_applicable_for_path_type() {
        check_assist_not_applicable(
            generate_enum_variant,
            r"
enum Foo {}
impl Foo::Bar$0 {}
",
        )
    }
}
<|endoftext|>