<commit_before>//! Atom-class implementation.

use std::ops::{BitXor, Sub, Range, RangeInclusive};
use std::iter::FromIterator;
use std::fmt::{self, Debug};

use regex_syntax;
use itertools::Itertools;

use super::{Atom, ByteOrChar, Element, Repetition, Sequence, Union, Step};
use util::set::{self, Contains};

// ----------------------------------------------------------------
// Class

/// Any member of a class of atoms
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum ClassMember<T: Atom> {
    /// A single atom
    Atom(T),

    /// A range of atoms
    Range(T, T)
}

impl<T: Atom> ClassMember<T> {
    /// Map the class-member's atoms to a different type
    pub fn map_atoms<U, F>(self, f: F) -> ClassMember<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        match self {
            ClassMember::Atom(a) => ClassMember::Atom(f(a)),
            ClassMember::Range(a, b) => ClassMember::Range(f(a), f(b))
        }
    }

    /// Get the number of individual atoms that this class member represents.
    pub fn len(&self) -> usize {
        match self {
            &ClassMember::Atom(_) => 1,
            &ClassMember::Range(first, last) => last.distance(&first),
        }
    }

    /// Fetch an iterator over each discrete value contained by this member.
    #[inline]
     pub fn iter(&self) -> impl Iterator<Item=T>
        where T: Step {
        match self {
            &ClassMember::Atom(a) => AtomIter(a...a),
            &ClassMember::Range(a, b) => AtomIter(a...b),
        }
    }
}

impl<T: Atom> set::Contains<T> for ClassMember<T> {
    /// Check if the member is or contains a particular atom.
    fn contains(&self, x: T) -> bool {
        match self {
            &ClassMember::Atom(a) => x == a,
            &ClassMember::Range(a, b) => (a...b).contains(x),
        }
    }
}

/// Iterator over the atoms specified by a class member.
struct AtomIter<T: Atom>(RangeInclusive<T>);

impl<T: Atom> Iterator for AtomIter<T>
        where T: Step
{
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            RangeInclusive::NonEmpty{start, end} => {
                let next_start = start.increment();
                if next_start > end {
                    self.0 = RangeInclusive::Empty{at: end};
                } else {
                    self.0 = RangeInclusive::NonEmpty{start: next_start, end: end};
                }
                Some(start) },
            RangeInclusive::Empty{..} => None
        }
    }
}

/*impl<T: Atom> Debug for ClassMember<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ClassMember::Atom(a) => write!(f, "{:?}", a),
            ClassMember::Range(first, last) => write!(f, "{:?}-{:?}", first, last)
        }
    }
}*/

impl<T: Atom> From<T> for ClassMember<T> {
    fn from(a: T) -> Self { ClassMember::Atom(a) }
}

impl From<regex_syntax::ClassRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ClassRange> for ClassMember<char> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<u8> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl<T: Atom> From<Range<T>> for ClassMember<T>
    where T: Sub<usize,Output=T> + Sub<T,Output=usize>
{
    fn from(r: Range<T>) -> Self {
        if r.end - r.start > 1 { ClassMember::Range(r.start, r.end - 1usize) }
        else { ClassMember::Atom(r.start) }
    }
}
// ----------------------------------------------------------------

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod class_impl {
    use std::slice;
    use super::ClassMember;
    pub type Inner<T> = Vec<ClassMember<T>>;
    pub type Iter<'a,T> = slice::Iter<'a,ClassMember<T>>;
}

/// A set of atoms and/or ranges of atoms.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Class<T: Atom> {
    polarity: Polarity,
    members: class_impl::Inner<T>
}

// FIXME: [optimize] All operations on a Class<T>, including observer and
// predicate methods, currently require at least O(N) time.  We could probably
// improve this by changing the storage representation.
impl<T: Atom> Class<T> {
    /// Create a new Class instance with specified polarity and members taken
    /// from the given iterator.
    pub fn new<I,U>(p: Polarity, items: I) -> Self
        where I: IntoIterator<Item=U>,
              ClassMember<T>: From<U> {
        Class{polarity: p, members: Vec::from_iter(items.into_iter().map(|x| x.into()))}
    }

    /// Map the atoms in the class to a different atom type.
    pub fn map_atoms<U, F>(self, f: F) -> Class<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        Class::new(self.polarity, self.members.into_iter().map(|m| m.map_atoms(&f)))
    }

    /// Check whether the class would match a particular atom.
    pub fn matches(&self, x: T) -> bool {
        self.has_member(x).bitxor(self.polarity == Polarity::NORMAL)
    }

    /// Check whether a particular atom is a member of this class.
    /// Unlike `matches`, this method does not take the class's polarity
    /// into account.
    pub fn has_member(&self, x: T) -> bool {
        self.members.iter().any(|&range| range.contains(x))
    }

    /// Get the number of members (atoms) in the class.
    ///
    /// Ranges of atoms count as the number of atoms in each range.
    // FIXME: [bug] handle inverted polarity?
    pub fn len(&self) -> usize {
        self.members.iter().map(|m| m.len()).sum()
    }

    /// Get the class's polarity.
    #[inline]
    pub fn polarity(&self) -> Polarity {
        self.polarity
    }

    /// Check if the class contains zero members.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.members.is_empty()
    }

    /// Fetch an iterator over the members specified in the class.
    ///
    /// Note that if the class has inverted polarity, the atoms in these
    /// members will be those which are **not** matched by the class.
    pub fn iter_members<'a>(&'a self) -> impl Iterator<Item=&'a ClassMember<T>> {
        self.members.iter()
    }
    }
}

impl<T: Atom> Debug for Class<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.polarity == Polarity::NORMAL {
            write!(f, "[{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        } else {
            write!(f, "[^{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        }
    }
}

impl<'a, T: 'a + Atom> set::Contains<&'a ClassMember<T>> for Class<T> {
    fn contains(&self, cm: &'a ClassMember<T>) -> bool {
        self.iter_members().any(|m| cm == m)
    }
}
impl<T: Atom> set::Contains<T> for Class<T> {
    fn contains(&self, x: T) -> bool {
        self.matches(x)
    }
}

// FIXME [optimize] I suspect that we need some sort of specialized data
// structure or clever algorithm in order to perform this test in a time better
// than O(N·M).
impl<T: Atom> set::IsSubsetOf<Class<T>> for Class<T> {
    fn is_subset_of(&self, other: &Self) -> bool {
        self.iter_members().flat_map(|m| m.iter()).all(|a| other.contains(a))
    }
}
impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Class<T> {
    /// Any single-atom pattern like Class cannot match the same set of inputs
    /// as a Sequence, because a Sequence is guaranteed to contain at least
    /// two elements.
    #[inline]
    fn is_subset_of(&self, _: &Sequence<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Class<T> {
    /// A class is a subset of a union if all members of the class are subsets
    /// of the union.
    fn is_subset_of(&self, _: &Union<T>) -> bool {
        unimplemented!()
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Class<T> {
    fn is_subset_of(&self, _: &Repetition<T>) -> bool {
        unimplemented!()
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Class<T> {
    fn is_subset_of(&self, other: &Element<T>) -> bool {
        match other {
            // Anything we can do, Wildcard can do betteeeeer...
            &Element::Wildcard => true,

            // A class *can* be a subset of an atom -- as long as that atom is
            // the only member of the class.
            &Element::Atom(a) => self.contains(a) && self.polarity == Polarity::NORMAL && self.len() == 1,
            &Element::Class(ref d) => self.is_subset_of(d),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Anchor(_) => false,
        }
    }
}

impl<T: Atom, U> FromIterator<U> for Class<T>
where ClassMember<T>: From<U> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=U> {
        Class{polarity: Polarity::NORMAL, members: Vec::from_iter(iter.into_iter().map(|x| x.into()))}
    }
}

macro_rules! impl_class_from {
    ($T: ty, $from: ty) => {
        impl<'a> From<$from> for Class<$T> {
            fn from(c: $from) -> Self {
                Self::new(Polarity::NORMAL,
                          c.into_iter().map(|cr| if cr.end != cr.start { ClassMember::Range(cr.start.into(), cr.end.into()) }
                                            else { ClassMember::Atom(cr.start.into()) }))
            }
        }
    };
}

impl_class_from!(char, regex_syntax::CharClass);
impl_class_from!(u8, regex_syntax::ByteClass);
impl_class_from!(ByteOrChar, regex_syntax::CharClass);
impl_class_from!(ByteOrChar, regex_syntax::ByteClass);

// ----------------------------------------------------------------

/** Flag type used to differentiate between normal and inverting matches on
 * pattern elements. */
#[derive(Debug,Copy,Clone,PartialEq, PartialOrd, Eq, Ord)]
pub enum Polarity {
    /// Normal match behavior.
    NORMAL,
    /// Invert the match result.
    INVERTED
}
<commit_msg>pattern/class: some simplifications and cleanup<commit_after>//! Atom-class implementation.

use std::ops::{BitXor, Sub, Range, RangeInclusive};
use std::iter::FromIterator;
use std::fmt::{self, Debug};

use regex_syntax;
use itertools::Itertools;

use super::{Atom, ByteOrChar, Element, Repetition, Sequence, Union};
use super::{Distance, Step};
use util::set::{self, Contains};

// ----------------------------------------------------------------
// Class

/// Any member of a class of atoms
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum ClassMember<T: Atom> {
    /// A single atom
    Atom(T),

    /// A range of atoms
    Range(T, T)
}

impl<T: Atom> ClassMember<T> {
    /// Map the class-member's atoms to a different type
    pub fn map_atoms<U, F>(self, f: F) -> ClassMember<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        match self {
            ClassMember::Atom(a) => ClassMember::Atom(f(a)),
            ClassMember::Range(a, b) => ClassMember::Range(f(a), f(b))
        }
    }

    /// Get the number of individual atoms that this class member represents.
    pub fn len(&self) -> usize {
        match self {
            &ClassMember::Atom(_) => 1,
            &ClassMember::Range(first, last) => last.distance(&first),
        }
    }

    /// Fetch an iterator over each discrete value contained by this member.
    #[inline]
     pub fn iter(&self) -> impl Iterator<Item=T>
        where T: Step {
        match self {
            &ClassMember::Atom(a) => AtomIter(a...a),
            &ClassMember::Range(a, b) => AtomIter(a...b),
        }
    }
}

impl<T: Atom> set::Contains<T> for ClassMember<T> {
    /// Check if the member is or contains a particular atom.
    fn contains(&self, x: T) -> bool {
        match self {
            &ClassMember::Atom(a) => x == a,
            &ClassMember::Range(a, b) => (a...b).contains(x),
        }
    }
}

/// Iterator over the atoms specified by a class member.
struct AtomIter<T: Atom>(RangeInclusive<T>);

impl<T: Atom> Iterator for AtomIter<T>
        where T: Step
{
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0 {
            RangeInclusive::NonEmpty{start, end} => {
                let next_start = start.increment();
                if next_start > end {
                    self.0 = RangeInclusive::Empty{at: end};
                } else {
                    self.0 = RangeInclusive::NonEmpty{start: next_start, end: end};
                }
                Some(start) },
            RangeInclusive::Empty{..} => None
        }
    }
}

/*impl<T: Atom> Debug for ClassMember<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ClassMember::Atom(a) => write!(f, "{:?}", a),
            ClassMember::Range(first, last) => write!(f, "{:?}-{:?}", first, last)
        }
    }
}*/

impl<T: Atom> From<T> for ClassMember<T> {
    fn from(a: T) -> Self { ClassMember::Atom(a) }
}

impl From<regex_syntax::ClassRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<ByteOrChar> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start.into(), cr.end.into())
    }
}

impl From<regex_syntax::ClassRange> for ClassMember<char> {
    fn from(cr: regex_syntax::ClassRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl From<regex_syntax::ByteRange> for ClassMember<u8> {
    fn from(cr: regex_syntax::ByteRange) -> Self {
        ClassMember::Range(cr.start, cr.end)
    }
}

impl<T: Atom> From<Range<T>> for ClassMember<T>
    where T: Sub<usize,Output=T> + Sub<T,Output=usize>
{
    fn from(r: Range<T>) -> Self {
        if r.end - r.start > 1 { ClassMember::Range(r.start, r.end - 1usize) }
        else { ClassMember::Atom(r.start) }
    }
}
// ----------------------------------------------------------------

/// A set of atoms and/or ranges of atoms.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord)]
pub struct Class<T: Atom> {
    polarity: Polarity,
    members: Vec<ClassMember<T>>
}

// FIXME: [optimize] All operations on a Class<T>, including observer and
// predicate methods, currently require at least O(N) time.  We could probably
// improve this by changing the storage representation.
impl<T: Atom> Class<T> {
    /// Create a new Class instance with specified polarity and members taken
    /// from the given iterator.
    pub fn new<I,U>(p: Polarity, items: I) -> Self
        where I: IntoIterator<Item=U>,
              ClassMember<T>: From<U> {
        Class{polarity: p, members: Vec::from_iter(items.into_iter().map(|x| x.into()))}
    }

    /// Map the atoms in the class to a different atom type.
    pub fn map_atoms<U, F>(self, f: F) -> Class<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        Class::new(self.polarity, self.members.into_iter().map(|m| m.map_atoms(&f)))
    }

    /// Check whether the class would match a particular atom.
    pub fn matches(&self, x: T) -> bool {
        self.has_member(x).bitxor(self.polarity == Polarity::NORMAL)
    }

    /// Check whether a particular atom is a member of this class.
    /// Unlike `matches`, this method does not take the class's polarity
    /// into account.
    pub fn has_member(&self, x: T) -> bool {
        self.members.iter().any(|&range| range.contains(x))
    }

    /// Get the number of members (atoms) in the class.
    ///
    /// Ranges of atoms count as the number of atoms in each range.
    // FIXME: [bug] handle inverted polarity?
    pub fn len(&self) -> usize {
        self.members.iter().map(|m| m.len()).sum()
    }

    /// Get the class's polarity.
    #[inline]
    pub fn polarity(&self) -> Polarity {
        self.polarity
    }

    /// Check if the class contains zero members.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.members.is_empty()
    }

    /// Fetch an iterator over the members specified in the class.
    ///
    /// Note that if the class has inverted polarity, the atoms in these
    /// members will be those which are **not** matched by the class.
    pub fn iter_members<'a>(&'a self) -> impl Iterator<Item=&'a ClassMember<T>> {
        self.members.iter()
    }
    }
}

impl<T: Atom> Debug for Class<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.polarity == Polarity::NORMAL {
            write!(f, "[{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        } else {
            write!(f, "[^{}]", self.members.iter().map(|m| format!("{:?}", m)).join(","))
        }
    }
}

impl<'a, T: 'a + Atom> set::Contains<&'a ClassMember<T>> for Class<T> {
    fn contains(&self, cm: &'a ClassMember<T>) -> bool {
        self.iter_members().any(|m| cm == m)
    }
}
impl<T: Atom> set::Contains<T> for Class<T> {
    fn contains(&self, x: T) -> bool {
        self.matches(x)
    }
}

// FIXME [optimize] I suspect that we need some sort of specialized data
// structure or clever algorithm in order to perform this test in a time better
// than O(N·M).
impl<T: Atom> set::IsSubsetOf<Class<T>> for Class<T> {
    fn is_subset_of(&self, other: &Self) -> bool {
        self.iter_members().flat_map(|m| m.iter()).all(|a| other.contains(a))
    }
}
impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Class<T> {
    /// Any single-atom pattern like Class cannot match the same set of inputs
    /// as a Sequence, because a Sequence is guaranteed to contain at least
    /// two elements.
    #[inline]
    fn is_subset_of(&self, _: &Sequence<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Class<T> {
    /// A class is a subset of a union if all members of the class are subsets
    /// of the union.
    fn is_subset_of(&self, _: &Union<T>) -> bool {
        unimplemented!()
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Class<T> {
    fn is_subset_of(&self, _: &Repetition<T>) -> bool {
        unimplemented!()
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Class<T> {
    fn is_subset_of(&self, other: &Element<T>) -> bool {
        match other {
            // Anything we can do, Wildcard can do betteeeeer...
            &Element::Wildcard => true,

            // A class *can* be a subset of an atom -- as long as that atom is
            // the only member of the class.
            &Element::Atom(a) => self.contains(a) && self.polarity == Polarity::NORMAL && self.len() == 1,
            &Element::Class(ref d) => self.is_subset_of(d),
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref seq) => self.is_subset_of(seq),
            &Element::Union(ref union) => self.is_subset_of(union),
            &Element::Repeat(ref rep) => self.is_subset_of(rep),
            &Element::Anchor(_) => false,
        }
    }
}

impl<T: Atom, U> FromIterator<U> for Class<T>
where ClassMember<T>: From<U> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=U> {
        Class{polarity: Polarity::NORMAL, members: Vec::from_iter(iter.into_iter().map(|x| x.into()))}
    }
}

macro_rules! impl_class_from {
    ($T: ty, $from: ty) => {
        impl<'a> From<$from> for Class<$T> {
            fn from(c: $from) -> Self {
                Self::new(Polarity::NORMAL,
                          c.into_iter().map(|cr| if cr.end != cr.start { ClassMember::Range(cr.start.into(), cr.end.into()) }
                                            else { ClassMember::Atom(cr.start.into()) }))
            }
        }
    };
}

impl_class_from!(char, regex_syntax::CharClass);
impl_class_from!(u8, regex_syntax::ByteClass);
impl_class_from!(ByteOrChar, regex_syntax::CharClass);
impl_class_from!(ByteOrChar, regex_syntax::ByteClass);

// ----------------------------------------------------------------

/** Flag type used to differentiate between normal and inverting matches on
 * pattern elements. */
#[derive(Debug,Copy,Clone,PartialEq, PartialOrd, Eq, Ord)]
pub enum Polarity {
    /// Normal match behavior.
    NORMAL,
    /// Invert the match result.
    INVERTED
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use leptonica_sys::{Boxa, Pix, Pixa, _IO_FILE};

include!(concat!(env!("OUT_DIR"), "/capi_bindings.rs"));
include!(concat!(env!("OUT_DIR"), "/public_types_bindings.rs"));

#[cfg(test)]
mod tests {
    use super::*;
    use leptonica_sys::{pixFreeData, pixRead};
    use std::ffi::CStr;
    use std::ffi::CString;
    use std::ptr;
    use std::str;

    #[test]
    fn ocr() {
        unsafe {
            let cube = TessBaseAPICreate();
            TessBaseAPIInit3(cube, ptr::null(), CString::new("eng").unwrap().as_ptr());
            let image = pixRead(CString::new("../img.png").unwrap().as_ptr());
            TessBaseAPISetImage2(cube, image);
            TessBaseAPIRecognize(cube, ptr::null_mut());
            assert_eq!(
                str::from_utf8(CStr::from_ptr(TessBaseAPIGetUTF8Text(cube)).to_bytes()),
                Ok(include_str!("../../img.txt"))
            );
            pixFreeData(image);
            TessBaseAPIDelete(cube);
        }
    }

    #[test]
    #[allow(path_statements)]
    fn defined_constants() {
        kMinCredibleResolution;
        kMaxCredibleResolution;
    }
}
<commit_msg>fix mac os build<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use leptonica_sys::*;

include!(concat!(env!("OUT_DIR"), "/capi_bindings.rs"));
include!(concat!(env!("OUT_DIR"), "/public_types_bindings.rs"));

#[cfg(test)]
mod tests {
    use super::*;
    use leptonica_sys::{pixFreeData, pixRead};
    use std::ffi::CStr;
    use std::ffi::CString;
    use std::ptr;
    use std::str;

    #[test]
    fn ocr() {
        unsafe {
            let cube = TessBaseAPICreate();
            TessBaseAPIInit3(cube, ptr::null(), CString::new("eng").unwrap().as_ptr());
            let image = pixRead(CString::new("../img.png").unwrap().as_ptr());
            TessBaseAPISetImage2(cube, image);
            TessBaseAPIRecognize(cube, ptr::null_mut());
            assert_eq!(
                str::from_utf8(CStr::from_ptr(TessBaseAPIGetUTF8Text(cube)).to_bytes()),
                Ok(include_str!("../../img.txt"))
            );
            pixFreeData(image);
            TessBaseAPIDelete(cube);
        }
    }

    #[test]
    #[allow(path_statements)]
    fn defined_constants() {
        kMinCredibleResolution;
        kMaxCredibleResolution;
    }
}
<|endoftext|>


<commit_before>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mock_function::MockFunction,
    mock_trait::MockTrait
};

fn phantom_default_inits(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .map(|(count, _param)| {
        let phident = format_ident!("_t{}", count);
        quote!(#phident: ::std::marker::PhantomData)
    }).collect()
}

/// Generate any PhantomData field definitions
fn phantom_fields(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .filter_map(|(count, param)| {
        let phident = format_ident!("_t{}", count);
        match param {
            syn::GenericParam::Lifetime(l) => {
                if !l.bounds.is_empty() {
                    compile_error(l.bounds.span(),
                        "#automock does not yet support lifetime bounds on structs");
                }
                let lifetime = &l.lifetime;
                Some(
                quote!(#phident: ::std::marker::PhantomData<&#lifetime ()>)
                )
            },
            syn::GenericParam::Type(tp) => {
                let ty = &tp.ident;
                Some(
                quote!(#phident: ::std::marker::PhantomData<#ty>)
                )
            },
            syn::GenericParam::Const(_) => {
                compile_error(param.span(),
                    "#automock does not yet support generic constants");
                None
            }
        }
    }).collect()
}

/// A collection of methods defined in one spot
struct Methods(Vec<MockFunction>);

impl Methods {
    fn calls(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.call(modname))
            .collect::<Vec<_>>()
    }

    fn checkpoints(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.checkpoint())
            .collect::<Vec<_>>()
    }

    fn contexts(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if !meth.is_static() {
                // Only static methods have context methods, but we need
                // something here so contexts will have the same length as
                // calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls, contexts, and
                // expects methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.context_fn(modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    /// Return a fragment of code to initialize struct fields during default()
    fn default_inits(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                let expectations_obj = &meth.expectations_obj();
                quote!(#attrs #name: #modname::#expectations_obj::default())
            }).collect::<Vec<_>>()
    }

    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.field_definition(Some(modname)))
            .collect::<Vec<_>>()
    }

    fn expects(&self, modname: &Ident) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if meth.is_static() {
                // static methods' expect methods are generated by the
                // Context objects, but we still need something here so
                // expects will have the same length as calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls and expects
                // methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.expect(&modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    fn priv_mods(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.priv_module())
            .collect::<Vec<_>>()
    }
}

pub(crate) struct MockItemStruct {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Does the original struct have a `new` method?
    has_new: bool,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Is this a whole MockStruct or just a substructure for a trait impl?
    traits: Vec<MockTrait>,
    vis: Visibility,
}

impl MockItemStruct {
    fn new_method(&self) -> impl ToTokens {
        if self.has_new {
            TokenStream::new()
        } else {
            quote!(
                /// Create a new mock object with no expectations.
                ///
                /// This method will not be generated if the real struct
                /// already has a `new` method.  However, it *will* be
                /// generated if the struct implements a trait with a `new`
                /// method.  The trait's `new` method can still be called
                /// like `<MockX as TraitY>::new`
                pub fn new() -> Self {
                    Self::default()
                }
            )
        }
    }

    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl From<MockableStruct> for MockItemStruct {
    fn from(mockable: MockableStruct) -> MockItemStruct {
        let mock_ident = gen_mod_ident(&mockable.name, None);
        let modname = gen_mod_ident(&mockable.original_name, None);
        let generics = mockable.generics.clone();
        let struct_name = &mockable.name;
        let vis = mockable.vis;
        let has_new = mockable.methods.iter()
            .any(|meth| meth.sig.ident == "new") ||
            mockable.traits.iter()
            .any(|trait_|
                trait_.items.iter()
                    .any(|ti| if let TraitItem::Method(tim) = ti {
                            tim.sig.ident == "new"
                        } else {
                            false
                        }
                    )
            );
        let methods = Methods(mockable.methods.into_iter()
            .map(|meth|
                mock_function::Builder::new(&meth.sig, &meth.vis)
                    .attrs(&meth.attrs)
                    .parent(&mock_ident)
                    .struct_(&struct_name)
                    .struct_generics(&generics)
                    .levels(2)
                    .call_levels(0)
                    .build()
            ).collect::<Vec<_>>());
        let structname = &mockable.name;
        let traits = mockable.traits.into_iter()
            .map(|t| MockTrait::new(structname, &generics, t, &vis))
            .collect();

        MockItemStruct {
            attrs: mockable.attrs,
            generics,
            has_new,
            methods,
            modname,
            name: mockable.name,
            traits,
            vis
        }
    }
}

impl ToTokens for MockItemStruct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl();
        let modname = &self.modname;
        let calls = self.methods.calls(Some(modname));
        let method_checkpoints = self.methods.checkpoints();
        let contexts = self.methods.contexts(Some(&modname));
        let expects = self.methods.expects(&modname);
        let new_method = self.new_method();
        let priv_mods = self.methods.priv_mods();
        let substructs = self.traits.iter()
            .map(|trait_| {
                MockItemTraitImpl {
                    attrs: trait_.attrs.clone(),
                    generics: self.generics.clone(),
                    fieldname: format_ident!("{}_expectations", trait_.name()),
                    methods: Methods(trait_.methods.clone()),
                    modname: format_ident!("{}_{}", &self.modname, trait_.name()),
                    name: format_ident!("{}_{}", &self.name, trait_.name()),
                }
            }).collect::<Vec<_>>();
        let substruct_expectations = self.traits.iter()
            .map(|trait_| format_ident!("{}_expectations", trait_.name()))
            .collect::<Vec<_>>();
        let mut field_definitions = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname #tg)
            }).collect::<Vec<_>>();
        field_definitions.extend(self.methods.field_definitions(&modname));
        field_definitions.extend(self.phantom_fields());
        let mut default_inits = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname::default())
            }).collect::<Vec<_>>();
        default_inits.extend(self.methods.default_inits(&modname));
        default_inits.extend(self.phantom_default_inits());
        let trait_impls = self.traits.iter()
            .map(|ss| {
                let modname = format_ident!("{}_{}", &self.modname, ss.name());
                ss.trait_impl(&modname)
            }).collect::<Vec<_>>();
        let vis = &self.vis;
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            #vis struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        // TODO: try removing the type names, and just use
                        // "default"
                        #(#default_inits),*
                    }
                }
            }
            #(#substructs)*
            impl #ig #struct_name #tg #wc {
                #(#calls #contexts #expects)*
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(self.#substruct_expectations.checkpoint();)*
                    #(#method_checkpoints)*
                }
                #new_method
            }
            #(#trait_impls)*
        ).to_tokens(tokens);
    }
}

pub(crate) struct MockItemTraitImpl {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Name of the field of this type in the parent's structure
    fieldname: Ident,
}

impl MockItemTraitImpl {
    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl ToTokens for MockItemTraitImpl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs_nodocs = format_attrs(&self.attrs, false);
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let method_checkpoints = self.methods.checkpoints();
        let mut default_inits = self.methods.default_inits(&modname);
        default_inits.extend(self.phantom_default_inits());
        let mut field_definitions = self.methods.field_definitions(&modname);
        field_definitions.extend(self.phantom_fields());
        let priv_mods = self.methods.priv_mods();
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #attrs_nodocs
            struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            impl #ig #struct_name #tg #wc {
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(#method_checkpoints)*
                }
            }
        ).to_tokens(tokens);
    }
}
<commit_msg>Slightly simplify initialization of mock structs.  No practical change.<commit_after>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mock_function::MockFunction,
    mock_trait::MockTrait
};

fn phantom_default_inits(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .map(|(count, _param)| {
        let phident = format_ident!("_t{}", count);
        quote!(#phident: ::std::marker::PhantomData)
    }).collect()
}

/// Generate any PhantomData field definitions
fn phantom_fields(generics: &Generics) -> Vec<TokenStream> {
    generics.params
    .iter()
    .enumerate()
    .filter_map(|(count, param)| {
        let phident = format_ident!("_t{}", count);
        match param {
            syn::GenericParam::Lifetime(l) => {
                if !l.bounds.is_empty() {
                    compile_error(l.bounds.span(),
                        "#automock does not yet support lifetime bounds on structs");
                }
                let lifetime = &l.lifetime;
                Some(
                quote!(#phident: ::std::marker::PhantomData<&#lifetime ()>)
                )
            },
            syn::GenericParam::Type(tp) => {
                let ty = &tp.ident;
                Some(
                quote!(#phident: ::std::marker::PhantomData<#ty>)
                )
            },
            syn::GenericParam::Const(_) => {
                compile_error(param.span(),
                    "#automock does not yet support generic constants");
                None
            }
        }
    }).collect()
}

/// A collection of methods defined in one spot
struct Methods(Vec<MockFunction>);

impl Methods {
    fn calls(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.call(modname))
            .collect::<Vec<_>>()
    }

    fn checkpoints(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.checkpoint())
            .collect::<Vec<_>>()
    }

    fn contexts(&self, modname: Option<&Ident>) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if !meth.is_static() {
                // Only static methods have context methods, but we need
                // something here so contexts will have the same length as
                // calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls, contexts, and
                // expects methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.context_fn(modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    /// Return a fragment of code to initialize struct fields during default()
    fn default_inits(&self) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| {
                let name = meth.name();
                let attrs = meth.format_attrs(false);
                quote!(#attrs #name: Default::default())
            }).collect::<Vec<_>>()
    }

    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
        self.0.iter()
            .filter(|meth| !meth.is_static())
            .map(|meth| meth.field_definition(Some(modname)))
            .collect::<Vec<_>>()
    }

    fn expects(&self, modname: &Ident) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| if meth.is_static() {
                // static methods' expect methods are generated by the
                // Context objects, but we still need something here so
                // expects will have the same length as calls.
                // TODO: after merging the 2020_refactor branch, eliminate
                // this hack by de-interleaving the calls and expects
                // methods.
                Box::new(TokenStream::new()) as Box<dyn ToTokens>
            } else {
                Box::new(meth.expect(&modname)) as Box<dyn ToTokens>
            }).collect::<Vec<_>>()
    }

    fn priv_mods(&self) -> Vec<impl ToTokens> {
        self.0.iter()
            .map(|meth| meth.priv_module())
            .collect::<Vec<_>>()
    }
}

pub(crate) struct MockItemStruct {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Does the original struct have a `new` method?
    has_new: bool,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Is this a whole MockStruct or just a substructure for a trait impl?
    traits: Vec<MockTrait>,
    vis: Visibility,
}

impl MockItemStruct {
    fn new_method(&self) -> impl ToTokens {
        if self.has_new {
            TokenStream::new()
        } else {
            quote!(
                /// Create a new mock object with no expectations.
                ///
                /// This method will not be generated if the real struct
                /// already has a `new` method.  However, it *will* be
                /// generated if the struct implements a trait with a `new`
                /// method.  The trait's `new` method can still be called
                /// like `<MockX as TraitY>::new`
                pub fn new() -> Self {
                    Self::default()
                }
            )
        }
    }

    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl From<MockableStruct> for MockItemStruct {
    fn from(mockable: MockableStruct) -> MockItemStruct {
        let mock_ident = gen_mod_ident(&mockable.name, None);
        let modname = gen_mod_ident(&mockable.original_name, None);
        let generics = mockable.generics.clone();
        let struct_name = &mockable.name;
        let vis = mockable.vis;
        let has_new = mockable.methods.iter()
            .any(|meth| meth.sig.ident == "new") ||
            mockable.traits.iter()
            .any(|trait_|
                trait_.items.iter()
                    .any(|ti| if let TraitItem::Method(tim) = ti {
                            tim.sig.ident == "new"
                        } else {
                            false
                        }
                    )
            );
        let methods = Methods(mockable.methods.into_iter()
            .map(|meth|
                mock_function::Builder::new(&meth.sig, &meth.vis)
                    .attrs(&meth.attrs)
                    .parent(&mock_ident)
                    .struct_(&struct_name)
                    .struct_generics(&generics)
                    .levels(2)
                    .call_levels(0)
                    .build()
            ).collect::<Vec<_>>());
        let structname = &mockable.name;
        let traits = mockable.traits.into_iter()
            .map(|t| MockTrait::new(structname, &generics, t, &vis))
            .collect();

        MockItemStruct {
            attrs: mockable.attrs,
            generics,
            has_new,
            methods,
            modname,
            name: mockable.name,
            traits,
            vis
        }
    }
}

impl ToTokens for MockItemStruct {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs = &self.attrs;
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl();
        let modname = &self.modname;
        let calls = self.methods.calls(Some(modname));
        let method_checkpoints = self.methods.checkpoints();
        let contexts = self.methods.contexts(Some(&modname));
        let expects = self.methods.expects(&modname);
        let new_method = self.new_method();
        let priv_mods = self.methods.priv_mods();
        let substructs = self.traits.iter()
            .map(|trait_| {
                MockItemTraitImpl {
                    attrs: trait_.attrs.clone(),
                    generics: self.generics.clone(),
                    fieldname: format_ident!("{}_expectations", trait_.name()),
                    methods: Methods(trait_.methods.clone()),
                    modname: format_ident!("{}_{}", &self.modname, trait_.name()),
                    name: format_ident!("{}_{}", &self.name, trait_.name()),
                }
            }).collect::<Vec<_>>();
        let substruct_expectations = self.traits.iter()
            .map(|trait_| format_ident!("{}_expectations", trait_.name()))
            .collect::<Vec<_>>();
        let mut field_definitions = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                let tyname = &ss.name;
                quote!(#fieldname: #tyname #tg)
            }).collect::<Vec<_>>();
        field_definitions.extend(self.methods.field_definitions(&modname));
        field_definitions.extend(self.phantom_fields());
        let mut default_inits = substructs.iter()
            .map(|ss| {
                let fieldname = &ss.fieldname;
                quote!(#fieldname: Default::default())
            }).collect::<Vec<_>>();
        default_inits.extend(self.methods.default_inits());
        default_inits.extend(self.phantom_default_inits());
        let trait_impls = self.traits.iter()
            .map(|ss| {
                let modname = format_ident!("{}_{}", &self.modname, ss.name());
                ss.trait_impl(&modname)
            }).collect::<Vec<_>>();
        let vis = &self.vis;
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #(#attrs)*
            #vis struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            #(#substructs)*
            impl #ig #struct_name #tg #wc {
                #(#calls #contexts #expects)*
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(self.#substruct_expectations.checkpoint();)*
                    #(#method_checkpoints)*
                }
                #new_method
            }
            #(#trait_impls)*
        ).to_tokens(tokens);
    }
}

pub(crate) struct MockItemTraitImpl {
    attrs: Vec<Attribute>,
    generics: Generics,
    /// Inherent methods of the mock struct
    methods: Methods,
    /// Name of the overall module that holds all of the mock stuff
    // TODO: base this on name so we can get rid of MockableStruct.original_name
    modname: Ident,
    name: Ident,
    /// Name of the field of this type in the parent's structure
    fieldname: Ident,
}

impl MockItemTraitImpl {
    fn phantom_default_inits(&self) -> Vec<TokenStream> {
        phantom_default_inits(&self.generics)
    }

    fn phantom_fields(&self) -> Vec<TokenStream> {
        phantom_fields(&self.generics)
    }
}

impl ToTokens for MockItemTraitImpl {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let attrs_nodocs = format_attrs(&self.attrs, false);
        let struct_name = &self.name;
        let (ig, tg, wc) = self.generics.split_for_impl(); //TODO
        let modname = &self.modname;
        let method_checkpoints = self.methods.checkpoints();
        let mut default_inits = self.methods.default_inits();
        default_inits.extend(self.phantom_default_inits());
        let mut field_definitions = self.methods.field_definitions(&modname);
        field_definitions.extend(self.phantom_fields());
        let priv_mods = self.methods.priv_mods();
        quote!(
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            pub mod #modname {
                use super::*;
                #(#priv_mods)*
            }
            #[allow(non_camel_case_types)]
            #[allow(non_snake_case)]
            #[allow(missing_docs)]
            #attrs_nodocs
            struct #struct_name #ig #wc
            {
                #(#field_definitions),*
            }
            impl #ig ::std::default::Default for #struct_name #tg #wc {
                fn default() -> Self {
                    Self {
                        #(#default_inits),*
                    }
                }
            }
            impl #ig #struct_name #tg #wc {
                /// Validate that all current expectations for all methods have
                /// been satisfied, and discard them.
                pub fn checkpoint(&mut self) {
                    #(#method_checkpoints)*
                }
            }
        ).to_tokens(tokens);
    }
}
<|endoftext|>


<commit_before>use crate::utils::{span_lint, span_lint_and_then};
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, impl_lint_pass};
use syntax::ast::*;
use syntax::attr;
use syntax::source_map::Span;
use syntax::symbol::LocalInternedString;
use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor};

declare_clippy_lint! {
    /// **What it does:** Checks for names that are very similar and thus confusing.
    ///
    /// **Why is this bad?** It's hard to distinguish between names that differ only
    /// by a single character.
    ///
    /// **Known problems:** None?
    ///
    /// **Example:**
    /// ```ignore
    /// let checked_exp = something;
    /// let checked_expr = something_else;
    /// ```
    pub SIMILAR_NAMES,
    pedantic,
    "similarly named items and bindings"
}

declare_clippy_lint! {
    /// **What it does:** Checks for too many variables whose name consists of a
    /// single character.
    ///
    /// **Why is this bad?** It's hard to memorize what a variable means without a
    /// descriptive name.
    ///
    /// **Known problems:** None?
    ///
    /// **Example:**
    /// ```ignore
    /// let (a, b, c, d, e, f, g) = (...);
    /// ```
    pub MANY_SINGLE_CHAR_NAMES,
    style,
    "too many single character bindings"
}

declare_clippy_lint! {
    /// **What it does:** Checks if you have variables whose name consists of just
    /// underscores and digits.
    ///
    /// **Why is this bad?** It's hard to memorize what a variable means without a
    /// descriptive name.
    ///
    /// **Known problems:** None?
    ///
    /// **Example:**
    /// ```rust
    /// let _1 = 1;
    /// let ___1 = 1;
    /// let __1___2 = 11;
    /// ```
    pub JUST_UNDERSCORES_AND_DIGITS,
    style,
    "unclear name"
}

#[derive(Copy, Clone)]
pub struct NonExpressiveNames {
    pub single_char_binding_names_threshold: u64,
}

impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);

struct ExistingName {
    interned: LocalInternedString,
    span: Span,
    len: usize,
    whitelist: &'static [&'static str],
}

struct SimilarNamesLocalVisitor<'a, 'tcx> {
    names: Vec<ExistingName>,
    cx: &'a EarlyContext<'tcx>,
    lint: &'a NonExpressiveNames,

    /// A stack of scopes containing the single-character bindings in each scope.
    single_char_names: Vec<Vec<Ident>>,
}

impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
    fn check_single_char_names(&self) {
        let num_single_char_names = self.single_char_names.iter().flatten().count();
        let threshold = self.lint.single_char_binding_names_threshold;
        if num_single_char_names as u64 >= threshold {
            let span = self
                .single_char_names
                .iter()
                .flatten()
                .map(|ident| ident.span)
                .collect::<Vec<_>>();
            span_lint(
                self.cx,
                MANY_SINGLE_CHAR_NAMES,
                span,
                &format!(
                    "{} bindings with single-character names in scope",
                    num_single_char_names
                ),
            );
        }
    }
}

// this list contains lists of names that are allowed to be similar
// the assumption is that no name is ever contained in multiple lists.
#[rustfmt::skip]
const WHITELIST: &[&[&str]] = &[
    &["parsed", "parser"],
    &["lhs", "rhs"],
    &["tx", "rx"],
    &["set", "get"],
    &["args", "arms"],
    &["qpath", "path"],
    &["lit", "lint"],
];

struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);

impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
    fn visit_pat(&mut self, pat: &'tcx Pat) {
        match pat.node {
            PatKind::Ident(_, ident, _) => self.check_ident(ident),
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if !field.is_shorthand {
                        self.visit_pat(&field.pat);
                    }
                }
            },
            _ => walk_pat(self, pat),
        }
    }
    fn visit_mac(&mut self, _mac: &Mac) {
        // do not check macs
    }
}

fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
    for &allow in WHITELIST {
        if whitelisted(interned_name, allow) {
            return Some(allow);
        }
    }
    None
}

fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
    list.iter()
        .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
}

impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
    fn check_short_ident(&mut self, ident: Ident) {
        // Ignore shadowing
        if self
            .0
            .single_char_names
            .iter()
            .flatten()
            .any(|id| id.name == ident.name)
        {
            return;
        }

        if let Some(scope) = &mut self.0.single_char_names.last_mut() {
            scope.push(ident);
        }
    }

    #[allow(clippy::too_many_lines)]
    fn check_ident(&mut self, ident: Ident) {
        let interned_name = ident.name.as_str();
        if interned_name.chars().any(char::is_uppercase) {
            return;
        }
        if interned_name.chars().all(|c| c.is_digit(10) || c == '_') {
            span_lint(
                self.0.cx,
                JUST_UNDERSCORES_AND_DIGITS,
                ident.span,
                "consider choosing a more descriptive name",
            );
            return;
        }
        let count = interned_name.chars().count();
        if count < 3 {
            if count == 1 {
                self.check_short_ident(ident);
            }
            return;
        }
        for existing_name in &self.0.names {
            if whitelisted(&interned_name, existing_name.whitelist) {
                continue;
            }
            let mut split_at = None;
            if existing_name.len > count {
                if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
                    continue;
                }
            } else if existing_name.len < count {
                if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
                    continue;
                }
            } else {
                let mut interned_chars = interned_name.chars();
                let mut existing_chars = existing_name.interned.chars();
                let first_i = interned_chars.next().expect("we know we have at least one char");
                let first_e = existing_chars.next().expect("we know we have at least one char");
                let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();

                if eq_or_numeric((first_i, first_e)) {
                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                    if eq_or_numeric((last_i, last_e)) {
                        if interned_chars
                            .zip(existing_chars)
                            .filter(|&ie| !eq_or_numeric(ie))
                            .count()
                            != 1
                        {
                            continue;
                        }
                    } else {
                        let second_last_i = interned_chars
                            .next_back()
                            .expect("we know we have at least three chars");
                        let second_last_e = existing_chars
                            .next_back()
                            .expect("we know we have at least three chars");
                        if !eq_or_numeric((second_last_i, second_last_e))
                            || second_last_i == '_'
                            || !interned_chars.zip(existing_chars).all(eq_or_numeric)
                        {
                            // allowed similarity foo_x, foo_y
                            // or too many chars differ (foo_x, boo_y) or (foox, booy)
                            continue;
                        }
                        split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                    }
                } else {
                    let second_i = interned_chars.next().expect("we know we have at least two chars");
                    let second_e = existing_chars.next().expect("we know we have at least two chars");
                    if !eq_or_numeric((second_i, second_e))
                        || second_i == '_'
                        || !interned_chars.zip(existing_chars).all(eq_or_numeric)
                    {
                        // allowed similarity x_foo, y_foo
                        // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                        continue;
                    }
                    split_at = interned_name.chars().next().map(char::len_utf8);
                }
            }
            span_lint_and_then(
                self.0.cx,
                SIMILAR_NAMES,
                ident.span,
                "binding's name is too similar to existing binding",
                |diag| {
                    diag.span_note(existing_name.span, "existing binding defined here");
                    if let Some(split) = split_at {
                        diag.span_help(
                            ident.span,
                            &format!(
                                "separate the discriminating character by an \
                                 underscore like: `{}_{}`",
                                &interned_name[..split],
                                &interned_name[split..]
                            ),
                        );
                    }
                },
            );
            return;
        }
        self.0.names.push(ExistingName {
            whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
            interned: interned_name,
            span: ident.span,
            len: count,
        });
    }
}

impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
    /// ensure scoping rules work
    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
        let n = self.names.len();
        let single_char_count = self.single_char_names.len();
        f(self);
        self.names.truncate(n);
        self.single_char_names.truncate(single_char_count);
    }
}

impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
    fn visit_local(&mut self, local: &'tcx Local) {
        if let Some(ref init) = local.init {
            self.apply(|this| walk_expr(this, &**init));
        }
        // add the pattern after the expression because the bindings aren't available
        // yet in the init
        // expression
        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
    }
    fn visit_block(&mut self, blk: &'tcx Block) {
        self.single_char_names.push(vec![]);

        self.apply(|this| walk_block(this, blk));

        self.check_single_char_names();
        self.single_char_names.pop();
    }
    fn visit_arm(&mut self, arm: &'tcx Arm) {
        self.single_char_names.push(vec![]);

        self.apply(|this| {
            // just go through the first pattern, as either all patterns
            // bind the same bindings or rustc would have errored much earlier
            SimilarNamesNameVisitor(this).visit_pat(&arm.pats[0]);
            this.apply(|this| walk_expr(this, &arm.body));
        });

        self.check_single_char_names();
        self.single_char_names.pop();
    }
    fn visit_item(&mut self, _: &Item) {
        // do not recurse into inner items
    }
    fn visit_mac(&mut self, _mac: &Mac) {
        // do not check macs
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
        if let ItemKind::Fn(ref decl, _, _, ref blk) = item.node {
            do_check(self, cx, &item.attrs, decl, blk);
        }
    }

    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &ImplItem) {
        if let ImplItemKind::Method(ref sig, ref blk) = item.node {
            do_check(self, cx, &item.attrs, &sig.decl, blk);
        }
    }
}

fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
    if !attr::contains_name(attrs, sym!(test)) {
        let mut visitor = SimilarNamesLocalVisitor {
            names: Vec::new(),
            cx,
            lint,
            single_char_names: vec![vec![]],
        };

        // initialize with function arguments
        for arg in &decl.inputs {
            SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat);
        }
        // walk all other bindings
        walk_block(&mut visitor, blk);

        visitor.check_single_char_names();
    }
}

/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
    debug_assert!(a_name.chars().count() < b_name.chars().count());
    let mut a_chars = a_name.chars();
    let mut b_chars = b_name.chars();
    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
        if a == b {
            continue;
        }
        if let Some(b2) = b_chars.next() {
            // check if there's just one character inserted
            return a != b2 || a_chars.ne(b_chars);
        } else {
            // tuple
            // ntuple
            return true;
        }
    }
    // for item in items
    true
}
<commit_msg>Auto merge of #4512 - mati865:rustup, r=phansch<commit_after>use crate::utils::{span_lint, span_lint_and_then};
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_tool_lint, impl_lint_pass};
use syntax::ast::*;
use syntax::attr;
use syntax::source_map::Span;
use syntax::symbol::LocalInternedString;
use syntax::visit::{walk_block, walk_expr, walk_pat, Visitor};

declare_clippy_lint! {
    /// **What it does:** Checks for names that are very similar and thus confusing.
    ///
    /// **Why is this bad?** It's hard to distinguish between names that differ only
    /// by a single character.
    ///
    /// **Known problems:** None?
    ///
    /// **Example:**
    /// ```ignore
    /// let checked_exp = something;
    /// let checked_expr = something_else;
    /// ```
    pub SIMILAR_NAMES,
    pedantic,
    "similarly named items and bindings"
}

declare_clippy_lint! {
    /// **What it does:** Checks for too many variables whose name consists of a
    /// single character.
    ///
    /// **Why is this bad?** It's hard to memorize what a variable means without a
    /// descriptive name.
    ///
    /// **Known problems:** None?
    ///
    /// **Example:**
    /// ```ignore
    /// let (a, b, c, d, e, f, g) = (...);
    /// ```
    pub MANY_SINGLE_CHAR_NAMES,
    style,
    "too many single character bindings"
}

declare_clippy_lint! {
    /// **What it does:** Checks if you have variables whose name consists of just
    /// underscores and digits.
    ///
    /// **Why is this bad?** It's hard to memorize what a variable means without a
    /// descriptive name.
    ///
    /// **Known problems:** None?
    ///
    /// **Example:**
    /// ```rust
    /// let _1 = 1;
    /// let ___1 = 1;
    /// let __1___2 = 11;
    /// ```
    pub JUST_UNDERSCORES_AND_DIGITS,
    style,
    "unclear name"
}

#[derive(Copy, Clone)]
pub struct NonExpressiveNames {
    pub single_char_binding_names_threshold: u64,
}

impl_lint_pass!(NonExpressiveNames => [SIMILAR_NAMES, MANY_SINGLE_CHAR_NAMES, JUST_UNDERSCORES_AND_DIGITS]);

struct ExistingName {
    interned: LocalInternedString,
    span: Span,
    len: usize,
    whitelist: &'static [&'static str],
}

struct SimilarNamesLocalVisitor<'a, 'tcx> {
    names: Vec<ExistingName>,
    cx: &'a EarlyContext<'tcx>,
    lint: &'a NonExpressiveNames,

    /// A stack of scopes containing the single-character bindings in each scope.
    single_char_names: Vec<Vec<Ident>>,
}

impl<'a, 'tcx> SimilarNamesLocalVisitor<'a, 'tcx> {
    fn check_single_char_names(&self) {
        let num_single_char_names = self.single_char_names.iter().flatten().count();
        let threshold = self.lint.single_char_binding_names_threshold;
        if num_single_char_names as u64 >= threshold {
            let span = self
                .single_char_names
                .iter()
                .flatten()
                .map(|ident| ident.span)
                .collect::<Vec<_>>();
            span_lint(
                self.cx,
                MANY_SINGLE_CHAR_NAMES,
                span,
                &format!(
                    "{} bindings with single-character names in scope",
                    num_single_char_names
                ),
            );
        }
    }
}

// this list contains lists of names that are allowed to be similar
// the assumption is that no name is ever contained in multiple lists.
#[rustfmt::skip]
const WHITELIST: &[&[&str]] = &[
    &["parsed", "parser"],
    &["lhs", "rhs"],
    &["tx", "rx"],
    &["set", "get"],
    &["args", "arms"],
    &["qpath", "path"],
    &["lit", "lint"],
];

struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);

impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
    fn visit_pat(&mut self, pat: &'tcx Pat) {
        match pat.node {
            PatKind::Ident(_, ident, _) => self.check_ident(ident),
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if !field.is_shorthand {
                        self.visit_pat(&field.pat);
                    }
                }
            },
            _ => walk_pat(self, pat),
        }
    }
    fn visit_mac(&mut self, _mac: &Mac) {
        // do not check macs
    }
}

fn get_whitelist(interned_name: &str) -> Option<&'static [&'static str]> {
    for &allow in WHITELIST {
        if whitelisted(interned_name, allow) {
            return Some(allow);
        }
    }
    None
}

fn whitelisted(interned_name: &str, list: &[&str]) -> bool {
    list.iter()
        .any(|&name| interned_name.starts_with(name) || interned_name.ends_with(name))
}

impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
    fn check_short_ident(&mut self, ident: Ident) {
        // Ignore shadowing
        if self
            .0
            .single_char_names
            .iter()
            .flatten()
            .any(|id| id.name == ident.name)
        {
            return;
        }

        if let Some(scope) = &mut self.0.single_char_names.last_mut() {
            scope.push(ident);
        }
    }

    #[allow(clippy::too_many_lines)]
    fn check_ident(&mut self, ident: Ident) {
        let interned_name = ident.name.as_str();
        if interned_name.chars().any(char::is_uppercase) {
            return;
        }
        if interned_name.chars().all(|c| c.is_digit(10) || c == '_') {
            span_lint(
                self.0.cx,
                JUST_UNDERSCORES_AND_DIGITS,
                ident.span,
                "consider choosing a more descriptive name",
            );
            return;
        }
        let count = interned_name.chars().count();
        if count < 3 {
            if count == 1 {
                self.check_short_ident(ident);
            }
            return;
        }
        for existing_name in &self.0.names {
            if whitelisted(&interned_name, existing_name.whitelist) {
                continue;
            }
            let mut split_at = None;
            if existing_name.len > count {
                if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned) {
                    continue;
                }
            } else if existing_name.len < count {
                if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned, &interned_name) {
                    continue;
                }
            } else {
                let mut interned_chars = interned_name.chars();
                let mut existing_chars = existing_name.interned.chars();
                let first_i = interned_chars.next().expect("we know we have at least one char");
                let first_e = existing_chars.next().expect("we know we have at least one char");
                let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();

                if eq_or_numeric((first_i, first_e)) {
                    let last_i = interned_chars.next_back().expect("we know we have at least two chars");
                    let last_e = existing_chars.next_back().expect("we know we have at least two chars");
                    if eq_or_numeric((last_i, last_e)) {
                        if interned_chars
                            .zip(existing_chars)
                            .filter(|&ie| !eq_or_numeric(ie))
                            .count()
                            != 1
                        {
                            continue;
                        }
                    } else {
                        let second_last_i = interned_chars
                            .next_back()
                            .expect("we know we have at least three chars");
                        let second_last_e = existing_chars
                            .next_back()
                            .expect("we know we have at least three chars");
                        if !eq_or_numeric((second_last_i, second_last_e))
                            || second_last_i == '_'
                            || !interned_chars.zip(existing_chars).all(eq_or_numeric)
                        {
                            // allowed similarity foo_x, foo_y
                            // or too many chars differ (foo_x, boo_y) or (foox, booy)
                            continue;
                        }
                        split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
                    }
                } else {
                    let second_i = interned_chars.next().expect("we know we have at least two chars");
                    let second_e = existing_chars.next().expect("we know we have at least two chars");
                    if !eq_or_numeric((second_i, second_e))
                        || second_i == '_'
                        || !interned_chars.zip(existing_chars).all(eq_or_numeric)
                    {
                        // allowed similarity x_foo, y_foo
                        // or too many chars differ (x_foo, y_boo) or (xfoo, yboo)
                        continue;
                    }
                    split_at = interned_name.chars().next().map(char::len_utf8);
                }
            }
            span_lint_and_then(
                self.0.cx,
                SIMILAR_NAMES,
                ident.span,
                "binding's name is too similar to existing binding",
                |diag| {
                    diag.span_note(existing_name.span, "existing binding defined here");
                    if let Some(split) = split_at {
                        diag.span_help(
                            ident.span,
                            &format!(
                                "separate the discriminating character by an \
                                 underscore like: `{}_{}`",
                                &interned_name[..split],
                                &interned_name[split..]
                            ),
                        );
                    }
                },
            );
            return;
        }
        self.0.names.push(ExistingName {
            whitelist: get_whitelist(&interned_name).unwrap_or(&[]),
            interned: interned_name,
            span: ident.span,
            len: count,
        });
    }
}

impl<'a, 'b> SimilarNamesLocalVisitor<'a, 'b> {
    /// ensure scoping rules work
    fn apply<F: for<'c> Fn(&'c mut Self)>(&mut self, f: F) {
        let n = self.names.len();
        let single_char_count = self.single_char_names.len();
        f(self);
        self.names.truncate(n);
        self.single_char_names.truncate(single_char_count);
    }
}

impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
    fn visit_local(&mut self, local: &'tcx Local) {
        if let Some(ref init) = local.init {
            self.apply(|this| walk_expr(this, &**init));
        }
        // add the pattern after the expression because the bindings aren't available
        // yet in the init
        // expression
        SimilarNamesNameVisitor(self).visit_pat(&*local.pat);
    }
    fn visit_block(&mut self, blk: &'tcx Block) {
        self.single_char_names.push(vec![]);

        self.apply(|this| walk_block(this, blk));

        self.check_single_char_names();
        self.single_char_names.pop();
    }
    fn visit_arm(&mut self, arm: &'tcx Arm) {
        self.single_char_names.push(vec![]);

        self.apply(|this| {
            // just go through the first pattern, as either all patterns
            // bind the same bindings or rustc would have errored much earlier
            SimilarNamesNameVisitor(this).visit_pat(&arm.pat);
            this.apply(|this| walk_expr(this, &arm.body));
        });

        self.check_single_char_names();
        self.single_char_names.pop();
    }
    fn visit_item(&mut self, _: &Item) {
        // do not recurse into inner items
    }
    fn visit_mac(&mut self, _mac: &Mac) {
        // do not check macs
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
        if let ItemKind::Fn(ref decl, _, _, ref blk) = item.node {
            do_check(self, cx, &item.attrs, decl, blk);
        }
    }

    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &ImplItem) {
        if let ImplItemKind::Method(ref sig, ref blk) = item.node {
            do_check(self, cx, &item.attrs, &sig.decl, blk);
        }
    }
}

fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
    if !attr::contains_name(attrs, sym!(test)) {
        let mut visitor = SimilarNamesLocalVisitor {
            names: Vec::new(),
            cx,
            lint,
            single_char_names: vec![vec![]],
        };

        // initialize with function arguments
        for arg in &decl.inputs {
            SimilarNamesNameVisitor(&mut visitor).visit_pat(&arg.pat);
        }
        // walk all other bindings
        walk_block(&mut visitor, blk);

        visitor.check_single_char_names();
    }
}

/// Precondition: `a_name.chars().count() < b_name.chars().count()`.
fn levenstein_not_1(a_name: &str, b_name: &str) -> bool {
    debug_assert!(a_name.chars().count() < b_name.chars().count());
    let mut a_chars = a_name.chars();
    let mut b_chars = b_name.chars();
    while let (Some(a), Some(b)) = (a_chars.next(), b_chars.next()) {
        if a == b {
            continue;
        }
        if let Some(b2) = b_chars.next() {
            // check if there's just one character inserted
            return a != b2 || a_chars.ne(b_chars);
        } else {
            // tuple
            // ntuple
            return true;
        }
    }
    // for item in items
    true
}
<|endoftext|>


<commit_before>//! Implementation of incremental re-parsing.
//!
//! We use two simple strategies for this:
//!   - if the edit modifies only a single token (like changing an identifier's
//!     letter), we replace only this token.
//!   - otherwise, we search for the nearest `{}` block which contains the edit
//!     and try to parse only this block.

use ra_parser::Reparser;
use ra_text_edit::AtomTextEdit;

use crate::{
    algo,
    parsing::{
        lexer::{lex_single_syntax_kind, tokenize, Token},
        text_token_source::TextTokenSource,
        text_tree_sink::TextTreeSink,
    },
    syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode},
    SyntaxError,
    SyntaxKind::*,
    TextRange, TextUnit, T,
};

pub(crate) fn incremental_reparse(
    node: &SyntaxNode,
    edit: &AtomTextEdit,
    errors: Vec<SyntaxError>,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    if let Some((green, old_range)) = reparse_token(node, &edit) {
        return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range));
    }

    if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
    }
    None
}

fn reparse_token<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, TextRange)> {
    let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
    let prev_token_kind = prev_token.kind();
    match prev_token_kind {
        WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
            if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
                // removing a new line may extends previous token
                let deleted_range = edit.delete - prev_token.text_range().start();
                if prev_token.text()[deleted_range].contains('\n') {
                    return None;
                }
            }

            let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
            let (new_token_kind, _error) = lex_single_syntax_kind(&new_text)?;

            if new_token_kind != prev_token_kind
                || (new_token_kind == IDENT && is_contextual_kw(&new_text))
            {
                return None;
            }

            // Check that edited token is not a part of the bigger token.
            // E.g. if for source code `bruh"str"` the user removed `ruh`, then
            // `b` no longer remains an identifier, but becomes a part of byte string literal
            if let Some(next_char) = root.text().char_at(prev_token.text_range().end()) {
                new_text.push(next_char);
                let token_with_next_char = lex_single_syntax_kind(&new_text);
                if let Some((_kind, _error)) = token_with_next_char {
                    return None;
                }
                new_text.pop();
            }

            let new_token =
                GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
            Some((prev_token.replace_with(new_token), prev_token.text_range()))
        }
        _ => None,
    }
}

fn reparse_block<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    let (node, reparser) = find_reparsable_node(root, edit.delete)?;
    let text = get_text_after_edit(node.clone().into(), edit);

    let (tokens, new_lexer_errors) = tokenize(&text);
    if !is_balanced(&tokens) {
        return None;
    }

    let mut token_source = TextTokenSource::new(&text, &tokens);
    let mut tree_sink = TextTreeSink::new(&text, &tokens);
    reparser.parse(&mut token_source, &mut tree_sink);

    let (green, mut new_parser_errors) = tree_sink.finish();
    new_parser_errors.extend(new_lexer_errors);

    Some((node.replace_with(green), new_parser_errors, node.text_range()))
}

fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
    let edit =
        AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone());

    let text = match element {
        NodeOrToken::Token(token) => token.text().to_string(),
        NodeOrToken::Node(node) => node.text().to_string(),
    };
    edit.apply(text)
}

fn is_contextual_kw(text: &str) -> bool {
    match text {
        "auto" | "default" | "union" => true,
        _ => false,
    }
}

fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
    let node = algo::find_covering_element(node, range);

    let mut ancestors = match node {
        NodeOrToken::Token(it) => it.parent().ancestors(),
        NodeOrToken::Node(it) => it.ancestors(),
    };
    ancestors.find_map(|node| {
        let first_child = node.first_child_or_token().map(|it| it.kind());
        let parent = node.parent().map(|it| it.kind());
        Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r))
    })
}

fn is_balanced(tokens: &[Token]) -> bool {
    if tokens.is_empty()
        || tokens.first().unwrap().kind != T!['{']
        || tokens.last().unwrap().kind != T!['}']
    {
        return false;
    }
    let mut balance = 0usize;
    for t in &tokens[1..tokens.len() - 1] {
        match t.kind {
            T!['{'] => balance += 1,
            T!['}'] => {
                balance = match balance.checked_sub(1) {
                    Some(b) => b,
                    None => return false,
                }
            }
            _ => (),
        }
    }
    balance == 0
}

fn merge_errors(
    old_errors: Vec<SyntaxError>,
    new_errors: Vec<SyntaxError>,
    range_before_reparse: TextRange,
    edit: &AtomTextEdit,
) -> Vec<SyntaxError> {
    let mut res = Vec::new();

    for old_err in old_errors {
        let old_err_range = *old_err.range();
        // FIXME: make sure that .start() was here previously by a mistake
        if old_err_range.end() <= range_before_reparse.start() {
            res.push(old_err);
        } else if old_err_range.start() >= range_before_reparse.end() {
            let inserted_len = TextUnit::of_str(&edit.insert);
            res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
            // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
        }
    }
    res.extend(new_errors.into_iter().map(|new_err| {
        // fighting borrow checker with a variable ;)
        let offseted_range = new_err.range() + range_before_reparse.start();
        new_err.with_range(offseted_range)
    }));
    res
}

#[cfg(test)]
mod tests {
    use test_utils::{assert_eq_text, extract_range};

    use super::*;
    use crate::{AstNode, Parse, SourceFile};

    fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
        let (range, before) = extract_range(before);
        let edit = AtomTextEdit::replace(range, replace_with.to_owned());
        let after = edit.apply(before.clone());

        let fully_reparsed = SourceFile::parse(&after);
        let incrementally_reparsed: Parse<SourceFile> = {
            let f = SourceFile::parse(&before);
            let (green, new_errors, range) =
                incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap();
            assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
            Parse::new(green, new_errors)
        };

        assert_eq_text!(
            &format!("{:#?}", fully_reparsed.tree().syntax()),
            &format!("{:#?}", incrementally_reparsed.tree().syntax()),
        );
    }

    #[test] // FIXME: some test here actually test token reparsing
    fn reparse_block_tests() {
        do_check(
            r"
fn foo() {
    let x = foo + <|>bar<|>
}
",
            "baz",
            3,
        );
        do_check(
            r"
fn foo() {
    let x = foo<|> + bar<|>
}
",
            "baz",
            25,
        );
        do_check(
            r"
struct Foo {
    f: foo<|><|>
}
",
            ",\n    g: (),",
            14,
        );
        do_check(
            r"
fn foo {
    let;
    1 + 1;
    <|>92<|>;
}
",
            "62",
            31, // FIXME: reparse only int literal here
        );
        do_check(
            r"
mod foo {
    fn <|><|>
}
",
            "bar",
            11,
        );

        do_check(
            r"
trait Foo {
    type <|>Foo<|>;
}
",
            "Output",
            3,
        );
        do_check(
            r"
impl IntoIterator<Item=i32> for Foo {
    f<|><|>
}
",
            "n next(",
            9,
        );
        do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10);
        do_check(
            r"
pub enum A {
    Foo<|><|>
}
",
            "\nBar;\n",
            11,
        );
        do_check(
            r"
foo!{a, b<|><|> d}
",
            ", c[3]",
            8,
        );
        do_check(
            r"
fn foo() {
    vec![<|><|>]
}
",
            "123",
            14,
        );
        do_check(
            r"
extern {
    fn<|>;<|>
}
",
            " exit(code: c_int)",
            11,
        );
    }

    #[test]
    fn reparse_token_tests() {
        do_check(
            r"<|><|>
fn foo() -> i32 { 1 }
",
            "\n\n\n   \n",
            1,
        );
        do_check(
            r"
fn foo() -> <|><|> {}
",
            "  \n",
            2,
        );
        do_check(
            r"
fn <|>foo<|>() -> i32 { 1 }
",
            "bar",
            3,
        );
        do_check(
            r"
fn foo<|><|>foo() {  }
",
            "bar",
            6,
        );
        do_check(
            r"
fn foo /* <|><|> */ () {}
",
            "some comment",
            6,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
/// foo <|><|>omment
mod { }
",
            "c",
            14,
        );
        do_check(
            r#"
fn -> &str { "Hello<|><|>" }
"#,
            ", world",
            7,
        );
        do_check(
            r#"
fn -> &str { // "Hello<|><|>"
"#,
            ", world",
            10,
        );
        do_check(
            r##"
fn -> &str { r#"Hello<|><|>"#
"##,
            ", world",
            10,
        );
        do_check(
            r"
#[derive(<|>Copy<|>)]
enum Foo {

}
",
            "Clone",
            4,
        );
    }
}
<commit_msg>ra_syntax: followup fix for making SyntaxError::range() to return by value<commit_after>//! Implementation of incremental re-parsing.
//!
//! We use two simple strategies for this:
//!   - if the edit modifies only a single token (like changing an identifier's
//!     letter), we replace only this token.
//!   - otherwise, we search for the nearest `{}` block which contains the edit
//!     and try to parse only this block.

use ra_parser::Reparser;
use ra_text_edit::AtomTextEdit;

use crate::{
    algo,
    parsing::{
        lexer::{lex_single_syntax_kind, tokenize, Token},
        text_token_source::TextTokenSource,
        text_tree_sink::TextTreeSink,
    },
    syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode},
    SyntaxError,
    SyntaxKind::*,
    TextRange, TextUnit, T,
};

pub(crate) fn incremental_reparse(
    node: &SyntaxNode,
    edit: &AtomTextEdit,
    errors: Vec<SyntaxError>,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    if let Some((green, old_range)) = reparse_token(node, &edit) {
        return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range));
    }

    if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
    }
    None
}

fn reparse_token<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, TextRange)> {
    let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
    let prev_token_kind = prev_token.kind();
    match prev_token_kind {
        WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
            if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
                // removing a new line may extends previous token
                let deleted_range = edit.delete - prev_token.text_range().start();
                if prev_token.text()[deleted_range].contains('\n') {
                    return None;
                }
            }

            let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
            let (new_token_kind, _error) = lex_single_syntax_kind(&new_text)?;

            if new_token_kind != prev_token_kind
                || (new_token_kind == IDENT && is_contextual_kw(&new_text))
            {
                return None;
            }

            // Check that edited token is not a part of the bigger token.
            // E.g. if for source code `bruh"str"` the user removed `ruh`, then
            // `b` no longer remains an identifier, but becomes a part of byte string literal
            if let Some(next_char) = root.text().char_at(prev_token.text_range().end()) {
                new_text.push(next_char);
                let token_with_next_char = lex_single_syntax_kind(&new_text);
                if let Some((_kind, _error)) = token_with_next_char {
                    return None;
                }
                new_text.pop();
            }

            let new_token =
                GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
            Some((prev_token.replace_with(new_token), prev_token.text_range()))
        }
        _ => None,
    }
}

fn reparse_block<'node>(
    root: &'node SyntaxNode,
    edit: &AtomTextEdit,
) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
    let (node, reparser) = find_reparsable_node(root, edit.delete)?;
    let text = get_text_after_edit(node.clone().into(), edit);

    let (tokens, new_lexer_errors) = tokenize(&text);
    if !is_balanced(&tokens) {
        return None;
    }

    let mut token_source = TextTokenSource::new(&text, &tokens);
    let mut tree_sink = TextTreeSink::new(&text, &tokens);
    reparser.parse(&mut token_source, &mut tree_sink);

    let (green, mut new_parser_errors) = tree_sink.finish();
    new_parser_errors.extend(new_lexer_errors);

    Some((node.replace_with(green), new_parser_errors, node.text_range()))
}

fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
    let edit =
        AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone());

    let text = match element {
        NodeOrToken::Token(token) => token.text().to_string(),
        NodeOrToken::Node(node) => node.text().to_string(),
    };
    edit.apply(text)
}

fn is_contextual_kw(text: &str) -> bool {
    match text {
        "auto" | "default" | "union" => true,
        _ => false,
    }
}

fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
    let node = algo::find_covering_element(node, range);

    let mut ancestors = match node {
        NodeOrToken::Token(it) => it.parent().ancestors(),
        NodeOrToken::Node(it) => it.ancestors(),
    };
    ancestors.find_map(|node| {
        let first_child = node.first_child_or_token().map(|it| it.kind());
        let parent = node.parent().map(|it| it.kind());
        Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r))
    })
}

fn is_balanced(tokens: &[Token]) -> bool {
    if tokens.is_empty()
        || tokens.first().unwrap().kind != T!['{']
        || tokens.last().unwrap().kind != T!['}']
    {
        return false;
    }
    let mut balance = 0usize;
    for t in &tokens[1..tokens.len() - 1] {
        match t.kind {
            T!['{'] => balance += 1,
            T!['}'] => {
                balance = match balance.checked_sub(1) {
                    Some(b) => b,
                    None => return false,
                }
            }
            _ => (),
        }
    }
    balance == 0
}

fn merge_errors(
    old_errors: Vec<SyntaxError>,
    new_errors: Vec<SyntaxError>,
    range_before_reparse: TextRange,
    edit: &AtomTextEdit,
) -> Vec<SyntaxError> {
    let mut res = Vec::new();

    for old_err in old_errors {
        let old_err_range = old_err.range();
        // FIXME: make sure that .start() was here previously by a mistake
        if old_err_range.end() <= range_before_reparse.start() {
            res.push(old_err);
        } else if old_err_range.start() >= range_before_reparse.end() {
            let inserted_len = TextUnit::of_str(&edit.insert);
            res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
            // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
        }
    }
    res.extend(new_errors.into_iter().map(|new_err| {
        // fighting borrow checker with a variable ;)
        let offseted_range = new_err.range() + range_before_reparse.start();
        new_err.with_range(offseted_range)
    }));
    res
}

#[cfg(test)]
mod tests {
    use test_utils::{assert_eq_text, extract_range};

    use super::*;
    use crate::{AstNode, Parse, SourceFile};

    fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
        let (range, before) = extract_range(before);
        let edit = AtomTextEdit::replace(range, replace_with.to_owned());
        let after = edit.apply(before.clone());

        let fully_reparsed = SourceFile::parse(&after);
        let incrementally_reparsed: Parse<SourceFile> = {
            let f = SourceFile::parse(&before);
            let (green, new_errors, range) =
                incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap();
            assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
            Parse::new(green, new_errors)
        };

        assert_eq_text!(
            &format!("{:#?}", fully_reparsed.tree().syntax()),
            &format!("{:#?}", incrementally_reparsed.tree().syntax()),
        );
    }

    #[test] // FIXME: some test here actually test token reparsing
    fn reparse_block_tests() {
        do_check(
            r"
fn foo() {
    let x = foo + <|>bar<|>
}
",
            "baz",
            3,
        );
        do_check(
            r"
fn foo() {
    let x = foo<|> + bar<|>
}
",
            "baz",
            25,
        );
        do_check(
            r"
struct Foo {
    f: foo<|><|>
}
",
            ",\n    g: (),",
            14,
        );
        do_check(
            r"
fn foo {
    let;
    1 + 1;
    <|>92<|>;
}
",
            "62",
            31, // FIXME: reparse only int literal here
        );
        do_check(
            r"
mod foo {
    fn <|><|>
}
",
            "bar",
            11,
        );

        do_check(
            r"
trait Foo {
    type <|>Foo<|>;
}
",
            "Output",
            3,
        );
        do_check(
            r"
impl IntoIterator<Item=i32> for Foo {
    f<|><|>
}
",
            "n next(",
            9,
        );
        do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10);
        do_check(
            r"
pub enum A {
    Foo<|><|>
}
",
            "\nBar;\n",
            11,
        );
        do_check(
            r"
foo!{a, b<|><|> d}
",
            ", c[3]",
            8,
        );
        do_check(
            r"
fn foo() {
    vec![<|><|>]
}
",
            "123",
            14,
        );
        do_check(
            r"
extern {
    fn<|>;<|>
}
",
            " exit(code: c_int)",
            11,
        );
    }

    #[test]
    fn reparse_token_tests() {
        do_check(
            r"<|><|>
fn foo() -> i32 { 1 }
",
            "\n\n\n   \n",
            1,
        );
        do_check(
            r"
fn foo() -> <|><|> {}
",
            "  \n",
            2,
        );
        do_check(
            r"
fn <|>foo<|>() -> i32 { 1 }
",
            "bar",
            3,
        );
        do_check(
            r"
fn foo<|><|>foo() {  }
",
            "bar",
            6,
        );
        do_check(
            r"
fn foo /* <|><|> */ () {}
",
            "some comment",
            6,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
fn baz <|><|> () {}
",
            "    \t\t\n\n",
            2,
        );
        do_check(
            r"
/// foo <|><|>omment
mod { }
",
            "c",
            14,
        );
        do_check(
            r#"
fn -> &str { "Hello<|><|>" }
"#,
            ", world",
            7,
        );
        do_check(
            r#"
fn -> &str { // "Hello<|><|>"
"#,
            ", world",
            10,
        );
        do_check(
            r##"
fn -> &str { r#"Hello<|><|>"#
"##,
            ", world",
            10,
        );
        do_check(
            r"
#[derive(<|>Copy<|>)]
enum Foo {

}
",
            "Clone",
            4,
        );
    }
}
<|endoftext|>