<commit_before>use crate::utils::{span_lint, span_lint_and_then};
use rustc_ast::ast::{
    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, MacCall, Pat, PatKind,
};
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;
use rustc_span::symbol::{Ident, Symbol};
use std::cmp::Ordering;

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: Symbol,
    span: Span,
    len: usize,
    exemptions: &'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 ALLOWED_TO_BE_SIMILAR: &[&[&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.kind {
            PatKind::Ident(_, ident, _) => {
                if !pat.span.from_expansion() {
                    self.check_ident(ident);
                }
            },
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if !field.is_shorthand {
                        self.visit_pat(&field.pat);
                    }
                }
            },
            // just go through the first pattern, as either all patterns
            // bind the same bindings or rustc would have errored much earlier
            PatKind::Or(ref pats) => self.visit_pat(&pats[0]),
            _ => walk_pat(self, pat),
        }
    }
    fn visit_mac(&mut self, _mac: &MacCall) {
        // do not check macs
    }
}

#[must_use]
fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> {
    for &list in ALLOWED_TO_BE_SIMILAR {
        if allowed_to_be_similar(interned_name, list) {
            return Some(list);
        }
    }
    None
}

#[must_use]
fn allowed_to_be_similar(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 allowed_to_be_similar(&interned_name, existing_name.exemptions) {
                continue;
            }
            let mut split_at = None;
            match existing_name.len.cmp(&count) {
                Ordering::Greater => {
                    if existing_name.len - count != 1
                        || levenstein_not_1(&interned_name, &existing_name.interned.as_str())
                    {
                        continue;
                    }
                },
                Ordering::Less => {
                    if count - existing_name.len != 1
                        || levenstein_not_1(&existing_name.interned.as_str(), &interned_name)
                    {
                        continue;
                    }
                },
                Ordering::Equal => {
                    let mut interned_chars = interned_name.chars();
                    let interned_str = existing_name.interned.as_str();
                    let mut existing_chars = interned_str.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 {
            exemptions: get_exemptions(&interned_name).unwrap_or(&[]),
            interned: ident.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| {
            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: &MacCall) {
        // do not check macs
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
        if in_external_macro(cx.sess, item.span) {
            return;
        }

        if let ItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind {
            do_check(self, cx, &item.attrs, &sig.decl, blk);
        }
    }

    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
        if in_external_macro(cx.sess, item.span) {
            return;
        }

        if let AssocItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind {
            do_check(self, cx, &item.attrs, &sig.decl, blk);
        }
    }
}

fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
    if !attrs.iter().any(|attr| attr.has_name(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()`.
#[must_use]
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>Rollup merge of #78710 - petrochenkov:macvisit, r=davidtwco<commit_after>use crate::utils::{span_lint, span_lint_and_then};
use rustc_ast::ast::{
    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
};
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;
use rustc_span::symbol::{Ident, Symbol};
use std::cmp::Ordering;

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: Symbol,
    span: Span,
    len: usize,
    exemptions: &'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 ALLOWED_TO_BE_SIMILAR: &[&[&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.kind {
            PatKind::Ident(_, ident, _) => {
                if !pat.span.from_expansion() {
                    self.check_ident(ident);
                }
            },
            PatKind::Struct(_, ref fields, _) => {
                for field in fields {
                    if !field.is_shorthand {
                        self.visit_pat(&field.pat);
                    }
                }
            },
            // just go through the first pattern, as either all patterns
            // bind the same bindings or rustc would have errored much earlier
            PatKind::Or(ref pats) => self.visit_pat(&pats[0]),
            _ => walk_pat(self, pat),
        }
    }
}

#[must_use]
fn get_exemptions(interned_name: &str) -> Option<&'static [&'static str]> {
    for &list in ALLOWED_TO_BE_SIMILAR {
        if allowed_to_be_similar(interned_name, list) {
            return Some(list);
        }
    }
    None
}

#[must_use]
fn allowed_to_be_similar(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 allowed_to_be_similar(&interned_name, existing_name.exemptions) {
                continue;
            }
            let mut split_at = None;
            match existing_name.len.cmp(&count) {
                Ordering::Greater => {
                    if existing_name.len - count != 1
                        || levenstein_not_1(&interned_name, &existing_name.interned.as_str())
                    {
                        continue;
                    }
                },
                Ordering::Less => {
                    if count - existing_name.len != 1
                        || levenstein_not_1(&existing_name.interned.as_str(), &interned_name)
                    {
                        continue;
                    }
                },
                Ordering::Equal => {
                    let mut interned_chars = interned_name.chars();
                    let interned_str = existing_name.interned.as_str();
                    let mut existing_chars = interned_str.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 {
            exemptions: get_exemptions(&interned_name).unwrap_or(&[]),
            interned: ident.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| {
            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
    }
}

impl EarlyLintPass for NonExpressiveNames {
    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
        if in_external_macro(cx.sess, item.span) {
            return;
        }

        if let ItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind {
            do_check(self, cx, &item.attrs, &sig.decl, blk);
        }
    }

    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
        if in_external_macro(cx.sess, item.span) {
            return;
        }

        if let AssocItemKind::Fn(_, ref sig, _, Some(ref blk)) = item.kind {
            do_check(self, cx, &item.attrs, &sig.decl, blk);
        }
    }
}

fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
    if !attrs.iter().any(|attr| attr.has_name(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()`.
#[must_use]
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>extern crate chrono;

use flowgger::Decoder;
use flowgger::config::Config;
use flowgger::record::{Record, StructuredData};
use self::chrono::DateTime;

#[derive(Clone)]
pub struct LTSVDecoder;

impl LTSVDecoder {
    pub fn new(config: &Config) -> LTSVDecoder {
        let _ = config;
        LTSVDecoder
    }
}

impl Decoder for LTSVDecoder {
    fn decode(&self, line: &str) -> Result<Record, &'static str> {
        let mut sd = StructuredData::new(None);
        let mut ts = None;
        let mut hostname = None;
        let mut msg = None;
        for part in line.split('\t') {
            let mut pair = part.splitn(2, ':');
            let name = try!(pair.next().ok_or("Missing name in an LTSV record"));
            let value = try!(pair.next().ok_or("Missing value in an LTSV record"));
            match name {
                "time" => {
                    let ts_s = if value.starts_with('[') && value.ends_with(']') {
                        &value[1..(value.len() -1)]
                    } else {
                        value
                    };
                    ts = Some(try!(parse_ts(ts_s)));
                },
                "host" => {
                    hostname = Some(value.to_owned())
                },
                "message" => {
                    msg = Some(value.to_owned());
                },
                name @ _ => {
                    sd.pairs.push((format!("_{}", name), value.to_owned()));
                }
            };
        }
        let record = Record {
            pri: None,
            ts: try!(ts.ok_or("Missing timestamp")),
            hostname: try!(hostname.ok_or("Missing hostname")),
            appname: None,
            procid: None,
            msgid: None,
            sd: if sd.pairs.is_empty() {
                    None
                } else {
                    Some(sd)
                },
            msg: msg
        };
        Ok(record)
    }
}

fn rfc3339_to_unix(rfc3339: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_rfc3339(rfc3339) {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn english_time_to_unix(et: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_str(et, "%e/%b/%Y:%H:%M:%S %z") {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn parse_ts(line: &str) -> Result<i64, &'static str> {
    rfc3339_to_unix(line).or(english_time_to_unix(line))
}

#[test]
fn test_ltsv() {
    let msg = "time:[2015-08-05T15:53:45.637824Z]\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3";
    let res = LTSVDecoder.decode(msg).unwrap();
    assert!(res.ts == 1438790025);

    let msg = "time:[10/Oct/2000:13:55:36 -0700]\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3";
    let res = LTSVDecoder.decode(msg).unwrap();
    assert!(res.ts == 971211336);

    assert!(res.hostname == "testhostname");
    let sd = res.sd.unwrap();
    let pairs = sd.pairs;
    assert!(pairs.iter().cloned().any(|(k, v)| k == "_name1" && v == "value1"));
    assert!(pairs.iter().cloned().any(|(k, v)| k == "_name 2" && v == " value 2"));
    assert!(pairs.iter().cloned().any(|(k, v)| k == "_n3" && v == "v3"));
}
<commit_msg>Save trees, remove superflous lines.<commit_after>extern crate chrono;

use flowgger::Decoder;
use flowgger::config::Config;
use flowgger::record::{Record, StructuredData};
use self::chrono::DateTime;

#[derive(Clone)]
pub struct LTSVDecoder;

impl LTSVDecoder {
    pub fn new(config: &Config) -> LTSVDecoder {
        let _ = config;
        LTSVDecoder
    }
}

impl Decoder for LTSVDecoder {
    fn decode(&self, line: &str) -> Result<Record, &'static str> {
        let mut sd = StructuredData::new(None);
        let mut ts = None;
        let mut hostname = None;
        let mut msg = None;
        for part in line.split('\t') {
            let mut pair = part.splitn(2, ':');
            let name = try!(pair.next().ok_or("Missing name in an LTSV record"));
            let value = try!(pair.next().ok_or("Missing value in an LTSV record"));
            match name {
                "time" => {
                    let ts_s = if value.starts_with('[') && value.ends_with(']') {
                        &value[1..(value.len() -1)]
                    } else {
                        value
                    };
                    ts = Some(try!(parse_ts(ts_s)));
                },
                "host" => hostname = Some(value.to_owned()),
                "message" => msg = Some(value.to_owned()),
                name @ _ => sd.pairs.push((format!("_{}", name), value.to_owned()))
            };
        }
        let record = Record {
            pri: None,
            ts: try!(ts.ok_or("Missing timestamp")),
            hostname: try!(hostname.ok_or("Missing hostname")),
            appname: None,
            procid: None,
            msgid: None,
            sd: if sd.pairs.is_empty() {
                    None
                } else {
                    Some(sd)
                },
            msg: msg
        };
        Ok(record)
    }
}

fn rfc3339_to_unix(rfc3339: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_rfc3339(rfc3339) {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn english_time_to_unix(et: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_str(et, "%e/%b/%Y:%H:%M:%S %z") {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn parse_ts(line: &str) -> Result<i64, &'static str> {
    rfc3339_to_unix(line).or(english_time_to_unix(line))
}

#[test]
fn test_ltsv() {
    let msg = "time:[2015-08-05T15:53:45.637824Z]\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3";
    let res = LTSVDecoder.decode(msg).unwrap();
    assert!(res.ts == 1438790025);

    let msg = "time:[10/Oct/2000:13:55:36 -0700]\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3";
    let res = LTSVDecoder.decode(msg).unwrap();
    assert!(res.ts == 971211336);

    assert!(res.hostname == "testhostname");
    let sd = res.sd.unwrap();
    let pairs = sd.pairs;
    assert!(pairs.iter().cloned().any(|(k, v)| k == "_name1" && v == "value1"));
    assert!(pairs.iter().cloned().any(|(k, v)| k == "_name 2" && v == " value 2"));
    assert!(pairs.iter().cloned().any(|(k, v)| k == "_n3" && v == "v3"));
}
<|endoftext|>


<commit_before>use crate::reflect::repeated::iter::ReflectRepeatedIter;
use crate::reflect::repeated::ReflectRepeated;
use crate::reflect::EnumDescriptor;
use crate::reflect::MessageDescriptor;
use crate::reflect::MessageRef;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;
use crate::MessageDyn;

/// Container of repeated values for dynamic messages.
///
/// It is logically similar to `Vec<ReflectValueBox>`, but:
/// * more efficient
/// * asserts all the elements are of the same type, the type which is specified at construction
#[derive(Debug, Clone)]
pub(crate) enum DynamicRepeated {
    U32(Vec<u32>),
    U64(Vec<u64>),
    I32(Vec<i32>),
    I64(Vec<i64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    Bool(Vec<bool>),
    String(Vec<String>),
    Bytes(Vec<Vec<u8>>),
    Enum(EnumDescriptor, Vec<i32>),
    Message(MessageDescriptor, Vec<Box<dyn MessageDyn>>),
}

impl ReflectRepeated for DynamicRepeated {
    fn reflect_iter(&self) -> ReflectRepeatedIter {
        unimplemented!()
    }

    fn len(&self) -> usize {
        match self {
            DynamicRepeated::U32(v) => v.len(),
            DynamicRepeated::U64(v) => v.len(),
            DynamicRepeated::I32(v) => v.len(),
            DynamicRepeated::I64(v) => v.len(),
            DynamicRepeated::F32(v) => v.len(),
            DynamicRepeated::F64(v) => v.len(),
            DynamicRepeated::Bool(v) => v.len(),
            DynamicRepeated::String(v) => v.len(),
            DynamicRepeated::Bytes(v) => v.len(),
            DynamicRepeated::Enum(.., v) => v.len(),
            DynamicRepeated::Message(.., v) => v.len(),
        }
    }

    fn get(&self, index: usize) -> ReflectValueRef {
        match self {
            DynamicRepeated::U32(v) => ReflectValueRef::U32(v[index]),
            DynamicRepeated::U64(v) => ReflectValueRef::U64(v[index]),
            DynamicRepeated::I32(v) => ReflectValueRef::I32(v[index]),
            DynamicRepeated::I64(v) => ReflectValueRef::I64(v[index]),
            DynamicRepeated::F32(v) => ReflectValueRef::F32(v[index]),
            DynamicRepeated::F64(v) => ReflectValueRef::F64(v[index]),
            DynamicRepeated::Bool(v) => ReflectValueRef::Bool(v[index]),
            DynamicRepeated::String(v) => ReflectValueRef::String(&v[index]),
            DynamicRepeated::Bytes(v) => ReflectValueRef::Bytes(&v[index]),
            DynamicRepeated::Enum(descriptor, v) => {
                ReflectValueRef::Enum(descriptor.clone(), v[index])
            }
            DynamicRepeated::Message(_descriptor, v) => {
                ReflectValueRef::Message(MessageRef::from(&*v[index]))
            }
        }
    }

    fn set(&mut self, index: usize, value: ReflectValueBox) {
        match self {
            DynamicRepeated::U32(v) => v.set(index, value),
            DynamicRepeated::U64(v) => v.set(index, value),
            DynamicRepeated::I32(v) => v.set(index, value),
            DynamicRepeated::I64(v) => v.set(index, value),
            DynamicRepeated::F32(v) => v.set(index, value),
            DynamicRepeated::F64(v) => v.set(index, value),
            DynamicRepeated::Bool(v) => v.set(index, value),
            DynamicRepeated::String(v) => v.set(index, value),
            DynamicRepeated::Bytes(v) => v.set(index, value),
            DynamicRepeated::Enum(descriptor, vs) => match value {
                ReflectValueBox::Enum(value_description, v) => {
                    assert_eq!(*descriptor, value_description);
                    vs[index] = v;
                }
                _ => panic!("Expected enum value"),
            },
            DynamicRepeated::Message(descriptor, vs) => match value {
                ReflectValueBox::Message(message) => {
                    assert_eq!(*descriptor, message.descriptor_dyn());
                    vs[index] = message;
                }
                _ => panic!("Expected message value"),
            },
        }
    }

    fn push(&mut self, value: ReflectValueBox) {
        match self {
            DynamicRepeated::U32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::U64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::I32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::I64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::F32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::F64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Bool(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::String(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Bytes(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Enum(descriptor, vs) => match value {
                ReflectValueBox::Enum(value_description, v) => {
                    assert_eq!(*descriptor, value_description);
                    vs.push(v);
                }
                _ => panic!("Expected enum value"),
            },
            DynamicRepeated::Message(descriptor, vs) => match value {
                ReflectValueBox::Message(message) => {
                    assert_eq!(*descriptor, message.descriptor_dyn());
                    vs.push(message);
                }
                _ => panic!("Expected message value"),
            },
        }
    }

    fn clear(&mut self) {
        match self {
            DynamicRepeated::U32(vs) => vs.clear(),
            DynamicRepeated::U64(vs) => vs.clear(),
            DynamicRepeated::I32(vs) => vs.clear(),
            DynamicRepeated::I64(vs) => vs.clear(),
            DynamicRepeated::F32(vs) => vs.clear(),
            DynamicRepeated::F64(vs) => vs.clear(),
            DynamicRepeated::Bool(vs) => vs.clear(),
            DynamicRepeated::String(vs) => vs.clear(),
            DynamicRepeated::Bytes(vs) => vs.clear(),
            DynamicRepeated::Enum(_descriptor, vs) => vs.clear(),
            DynamicRepeated::Message(_descriptor, vs) => vs.clear(),
        }
    }

    fn element_type(&self) -> RuntimeTypeBox {
        match self {
            DynamicRepeated::U32(..) => RuntimeTypeBox::U32,
            DynamicRepeated::U64(..) => RuntimeTypeBox::U64,
            DynamicRepeated::I32(..) => RuntimeTypeBox::I32,
            DynamicRepeated::I64(..) => RuntimeTypeBox::I64,
            DynamicRepeated::F32(..) => RuntimeTypeBox::F32,
            DynamicRepeated::F64(..) => RuntimeTypeBox::F64,
            DynamicRepeated::Bool(..) => RuntimeTypeBox::Bool,
            DynamicRepeated::String(..) => RuntimeTypeBox::String,
            DynamicRepeated::Bytes(..) => RuntimeTypeBox::VecU8,
            DynamicRepeated::Enum(descriptor, _vs) => RuntimeTypeBox::Enum(descriptor.clone()),
            DynamicRepeated::Message(descriptor, _vs) => {
                RuntimeTypeBox::Message(descriptor.clone())
            }
        }
    }

    fn data_enum_values(&self) -> &[i32] {
        match self {
            DynamicRepeated::Enum(_descriptor, vs) => &vs,
            _ => panic!("Expected enum value"),
        }
    }

    fn data_bool(&self) -> &[bool] {
        match self {
            DynamicRepeated::Bool(vs) => &vs,
            _ => panic!("Expected bool value"),
        }
    }

    fn data_u32(&self) -> &[u32] {
        match self {
            DynamicRepeated::U32(vs) => &vs,
            _ => panic!("Expected u32 value"),
        }
    }

    fn data_u64(&self) -> &[u64] {
        match self {
            DynamicRepeated::U64(vs) => &vs,
            _ => panic!("Expected u64 value"),
        }
    }

    fn data_i32(&self) -> &[i32] {
        match self {
            DynamicRepeated::I32(vs) => &vs,
            _ => panic!("Expected i32 value"),
        }
    }

    fn data_i64(&self) -> &[i64] {
        match self {
            DynamicRepeated::I64(vs) => &vs,
            _ => panic!("Expected i64 value"),
        }
    }

    fn data_f32(&self) -> &[f32] {
        match self {
            DynamicRepeated::F32(vs) => &vs,
            _ => panic!("Expected f32 value"),
        }
    }

    fn data_f64(&self) -> &[f64] {
        match self {
            DynamicRepeated::F64(vs) => &vs,
            _ => panic!("Expected f64 value"),
        }
    }
}

impl DynamicRepeated {
    pub fn new(elem: RuntimeTypeBox) -> DynamicRepeated {
        match elem {
            RuntimeTypeBox::U32 => DynamicRepeated::U32(Vec::new()),
            RuntimeTypeBox::U64 => DynamicRepeated::U64(Vec::new()),
            RuntimeTypeBox::I32 => DynamicRepeated::I32(Vec::new()),
            RuntimeTypeBox::I64 => DynamicRepeated::I64(Vec::new()),
            RuntimeTypeBox::F32 => DynamicRepeated::F32(Vec::new()),
            RuntimeTypeBox::F64 => DynamicRepeated::F64(Vec::new()),
            RuntimeTypeBox::Bool => DynamicRepeated::Bool(Vec::new()),
            RuntimeTypeBox::String => DynamicRepeated::String(Vec::new()),
            RuntimeTypeBox::VecU8 => DynamicRepeated::Bytes(Vec::new()),
            RuntimeTypeBox::Enum(enum_descriptor) => {
                DynamicRepeated::Enum(enum_descriptor, Vec::new())
            }
            RuntimeTypeBox::Message(message_descriptor) => {
                DynamicRepeated::Message(message_descriptor, Vec::new())
            }
        }
    }
}
<commit_msg>Implement iteration for some DynamicRepeated<commit_after>use crate::reflect::repeated::iter::ReflectRepeatedIter;
use crate::reflect::repeated::ReflectRepeated;
use crate::reflect::EnumDescriptor;
use crate::reflect::MessageDescriptor;
use crate::reflect::MessageRef;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;
use crate::MessageDyn;

/// Container of repeated values for dynamic messages.
///
/// It is logically similar to `Vec<ReflectValueBox>`, but:
/// * more efficient
/// * asserts all the elements are of the same type, the type which is specified at construction
#[derive(Debug, Clone)]
pub(crate) enum DynamicRepeated {
    U32(Vec<u32>),
    U64(Vec<u64>),
    I32(Vec<i32>),
    I64(Vec<i64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    Bool(Vec<bool>),
    String(Vec<String>),
    Bytes(Vec<Vec<u8>>),
    Enum(EnumDescriptor, Vec<i32>),
    Message(MessageDescriptor, Vec<Box<dyn MessageDyn>>),
}

impl ReflectRepeated for DynamicRepeated {
    fn reflect_iter(&self) -> ReflectRepeatedIter {
        match self {
            DynamicRepeated::U32(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::U64(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::I32(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::I64(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::F32(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::F64(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::Bool(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::String(v) => ReflectRepeatedIter::new_slice(&v),
            DynamicRepeated::Bytes(v) => ReflectRepeatedIter::new_slice(&v),
            _ => unimplemented!(),
        }
    }

    fn len(&self) -> usize {
        match self {
            DynamicRepeated::U32(v) => v.len(),
            DynamicRepeated::U64(v) => v.len(),
            DynamicRepeated::I32(v) => v.len(),
            DynamicRepeated::I64(v) => v.len(),
            DynamicRepeated::F32(v) => v.len(),
            DynamicRepeated::F64(v) => v.len(),
            DynamicRepeated::Bool(v) => v.len(),
            DynamicRepeated::String(v) => v.len(),
            DynamicRepeated::Bytes(v) => v.len(),
            DynamicRepeated::Enum(.., v) => v.len(),
            DynamicRepeated::Message(.., v) => v.len(),
        }
    }

    fn get(&self, index: usize) -> ReflectValueRef {
        match self {
            DynamicRepeated::U32(v) => ReflectValueRef::U32(v[index]),
            DynamicRepeated::U64(v) => ReflectValueRef::U64(v[index]),
            DynamicRepeated::I32(v) => ReflectValueRef::I32(v[index]),
            DynamicRepeated::I64(v) => ReflectValueRef::I64(v[index]),
            DynamicRepeated::F32(v) => ReflectValueRef::F32(v[index]),
            DynamicRepeated::F64(v) => ReflectValueRef::F64(v[index]),
            DynamicRepeated::Bool(v) => ReflectValueRef::Bool(v[index]),
            DynamicRepeated::String(v) => ReflectValueRef::String(&v[index]),
            DynamicRepeated::Bytes(v) => ReflectValueRef::Bytes(&v[index]),
            DynamicRepeated::Enum(descriptor, v) => {
                ReflectValueRef::Enum(descriptor.clone(), v[index])
            }
            DynamicRepeated::Message(_descriptor, v) => {
                ReflectValueRef::Message(MessageRef::from(&*v[index]))
            }
        }
    }

    fn set(&mut self, index: usize, value: ReflectValueBox) {
        match self {
            DynamicRepeated::U32(v) => v.set(index, value),
            DynamicRepeated::U64(v) => v.set(index, value),
            DynamicRepeated::I32(v) => v.set(index, value),
            DynamicRepeated::I64(v) => v.set(index, value),
            DynamicRepeated::F32(v) => v.set(index, value),
            DynamicRepeated::F64(v) => v.set(index, value),
            DynamicRepeated::Bool(v) => v.set(index, value),
            DynamicRepeated::String(v) => v.set(index, value),
            DynamicRepeated::Bytes(v) => v.set(index, value),
            DynamicRepeated::Enum(descriptor, vs) => match value {
                ReflectValueBox::Enum(value_description, v) => {
                    assert_eq!(*descriptor, value_description);
                    vs[index] = v;
                }
                _ => panic!("Expected enum value"),
            },
            DynamicRepeated::Message(descriptor, vs) => match value {
                ReflectValueBox::Message(message) => {
                    assert_eq!(*descriptor, message.descriptor_dyn());
                    vs[index] = message;
                }
                _ => panic!("Expected message value"),
            },
        }
    }

    fn push(&mut self, value: ReflectValueBox) {
        match self {
            DynamicRepeated::U32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::U64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::I32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::I64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::F32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::F64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Bool(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::String(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Bytes(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Enum(descriptor, vs) => match value {
                ReflectValueBox::Enum(value_description, v) => {
                    assert_eq!(*descriptor, value_description);
                    vs.push(v);
                }
                _ => panic!("Expected enum value"),
            },
            DynamicRepeated::Message(descriptor, vs) => match value {
                ReflectValueBox::Message(message) => {
                    assert_eq!(*descriptor, message.descriptor_dyn());
                    vs.push(message);
                }
                _ => panic!("Expected message value"),
            },
        }
    }

    fn clear(&mut self) {
        match self {
            DynamicRepeated::U32(vs) => vs.clear(),
            DynamicRepeated::U64(vs) => vs.clear(),
            DynamicRepeated::I32(vs) => vs.clear(),
            DynamicRepeated::I64(vs) => vs.clear(),
            DynamicRepeated::F32(vs) => vs.clear(),
            DynamicRepeated::F64(vs) => vs.clear(),
            DynamicRepeated::Bool(vs) => vs.clear(),
            DynamicRepeated::String(vs) => vs.clear(),
            DynamicRepeated::Bytes(vs) => vs.clear(),
            DynamicRepeated::Enum(_descriptor, vs) => vs.clear(),
            DynamicRepeated::Message(_descriptor, vs) => vs.clear(),
        }
    }

    fn element_type(&self) -> RuntimeTypeBox {
        match self {
            DynamicRepeated::U32(..) => RuntimeTypeBox::U32,
            DynamicRepeated::U64(..) => RuntimeTypeBox::U64,
            DynamicRepeated::I32(..) => RuntimeTypeBox::I32,
            DynamicRepeated::I64(..) => RuntimeTypeBox::I64,
            DynamicRepeated::F32(..) => RuntimeTypeBox::F32,
            DynamicRepeated::F64(..) => RuntimeTypeBox::F64,
            DynamicRepeated::Bool(..) => RuntimeTypeBox::Bool,
            DynamicRepeated::String(..) => RuntimeTypeBox::String,
            DynamicRepeated::Bytes(..) => RuntimeTypeBox::VecU8,
            DynamicRepeated::Enum(descriptor, _vs) => RuntimeTypeBox::Enum(descriptor.clone()),
            DynamicRepeated::Message(descriptor, _vs) => {
                RuntimeTypeBox::Message(descriptor.clone())
            }
        }
    }

    fn data_enum_values(&self) -> &[i32] {
        match self {
            DynamicRepeated::Enum(_descriptor, vs) => &vs,
            _ => panic!("Expected enum value"),
        }
    }

    fn data_bool(&self) -> &[bool] {
        match self {
            DynamicRepeated::Bool(vs) => &vs,
            _ => panic!("Expected bool value"),
        }
    }

    fn data_u32(&self) -> &[u32] {
        match self {
            DynamicRepeated::U32(vs) => &vs,
            _ => panic!("Expected u32 value"),
        }
    }

    fn data_u64(&self) -> &[u64] {
        match self {
            DynamicRepeated::U64(vs) => &vs,
            _ => panic!("Expected u64 value"),
        }
    }

    fn data_i32(&self) -> &[i32] {
        match self {
            DynamicRepeated::I32(vs) => &vs,
            _ => panic!("Expected i32 value"),
        }
    }

    fn data_i64(&self) -> &[i64] {
        match self {
            DynamicRepeated::I64(vs) => &vs,
            _ => panic!("Expected i64 value"),
        }
    }

    fn data_f32(&self) -> &[f32] {
        match self {
            DynamicRepeated::F32(vs) => &vs,
            _ => panic!("Expected f32 value"),
        }
    }

    fn data_f64(&self) -> &[f64] {
        match self {
            DynamicRepeated::F64(vs) => &vs,
            _ => panic!("Expected f64 value"),
        }
    }
}

impl DynamicRepeated {
    pub fn new(elem: RuntimeTypeBox) -> DynamicRepeated {
        match elem {
            RuntimeTypeBox::U32 => DynamicRepeated::U32(Vec::new()),
            RuntimeTypeBox::U64 => DynamicRepeated::U64(Vec::new()),
            RuntimeTypeBox::I32 => DynamicRepeated::I32(Vec::new()),
            RuntimeTypeBox::I64 => DynamicRepeated::I64(Vec::new()),
            RuntimeTypeBox::F32 => DynamicRepeated::F32(Vec::new()),
            RuntimeTypeBox::F64 => DynamicRepeated::F64(Vec::new()),
            RuntimeTypeBox::Bool => DynamicRepeated::Bool(Vec::new()),
            RuntimeTypeBox::String => DynamicRepeated::String(Vec::new()),
            RuntimeTypeBox::VecU8 => DynamicRepeated::Bytes(Vec::new()),
            RuntimeTypeBox::Enum(enum_descriptor) => {
                DynamicRepeated::Enum(enum_descriptor, Vec::new())
            }
            RuntimeTypeBox::Message(message_descriptor) => {
                DynamicRepeated::Message(message_descriptor, Vec::new())
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use spin::Once;
use memory::MemoryController;
use x86::bits64::task::TaskStateSegment;

mod idt;
mod gdt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

static IDT: Once<idt::Idt> = Once::new();
static TSS: Once<TaskStateSegment> = Once::new();
static GDT: Once<gdt::Gdt> = Once::new();

pub fn init(memory_controller: &mut MemoryController) {
    let double_fault_stack = memory_controller.alloc_stack(1)
        .expect("could not allocate double fault stack");

    const DOUBLE_FAULT_IST_INDEX: u8 = 0;

    let tss = TSS.call_once(|| {
        let mut tss = TaskStateSegment::new();
        tss.ist[DOUBLE_FAULT_IST_INDEX as usize] = double_fault_stack.top() as u64;
        tss
    });

    let mut code_selector = gdt::Selector::new();
    let mut data_selector = gdt::Selector::new();
    let mut tss_selector = gdt::Selector::new();
    let gdt = GDT.call_once(|| {
        let mut gdt = gdt::Gdt::new();

        code_selector = gdt.add_entry(gdt::Entry::code_segment());
        data_selector = gdt.add_entry(gdt::Entry::data_segment());
        tss_selector = gdt.add_entry(gdt::Entry::tss_segment(tss));

        gdt
    });
    gdt.load();
    gdt::reload_segment_registers(code_selector, data_selector);
    unsafe { gdt::load_ltr(tss_selector) };

    let idt = IDT.call_once(|| {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(8, handler_with_error_code!(double_fault_handler))
            .set_stack_index(DOUBLE_FAULT_IST_INDEX);
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    });

    idt.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame, error_code: u64) {
    use x86::shared::control_regs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { control_regs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}

extern "C" fn double_fault_handler(stack_frame: &ExceptionStackFrame, _error_code: u64) {
    println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
    loop {}
}
<commit_msg>Rewrite interrupts::init using a lazy_static IDT again<commit_after>// Copyright 2016 Philipp Oppermann. See the README.md
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use spin::Once;
use memory::MemoryController;
use x86::bits64::task::TaskStateSegment;

mod idt;
mod gdt;

macro_rules! save_scratch_registers {
    () => {
        asm!("push rax
              push rcx
              push rdx
              push rsi
              push rdi
              push r8
              push r9
              push r10
              push r11
        " :::: "intel", "volatile");
    }
}

macro_rules! restore_scratch_registers {
    () => {
        asm!("pop r11
              pop r10
              pop r9
              pop r8
              pop rdi
              pop rsi
              pop rdx
              pop rcx
              pop rax
            " :::: "intel", "volatile");
    }
}

macro_rules! handler {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rdi, rsp
                      add rdi, 9*8 // calculate exception stack frame pointer
                      call $0"
                      :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame))
                      : "rdi" : "intel");

                restore_scratch_registers!();
                asm!("iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

macro_rules! handler_with_error_code {
    ($name: ident) => {{
        #[naked]
        extern "C" fn wrapper() -> ! {
            unsafe {
                save_scratch_registers!();
                asm!("mov rsi, [rsp + 9*8] // load error code into rsi
                      mov rdi, rsp
                      add rdi, 10*8 // calculate exception stack frame pointer
                      sub rsp, 8 // align the stack pointer
                      call $0
                      add rsp, 8 // undo stack pointer alignment
                      " :: "i"($name as extern "C" fn(
                          &ExceptionStackFrame, u64))
                      : "rdi","rsi" : "intel");
                restore_scratch_registers!();
                asm!("add rsp, 8 // pop error code
                      iretq" :::: "intel", "volatile");
                ::core::intrinsics::unreachable();
            }
        }
        wrapper
    }}
}

lazy_static! {
    static ref IDT: idt::Idt = {
        let mut idt = idt::Idt::new();

        idt.set_handler(0, handler!(divide_by_zero_handler));
        idt.set_handler(3, handler!(breakpoint_handler));
        idt.set_handler(6, handler!(invalid_opcode_handler));
        idt.set_handler(8, handler_with_error_code!(double_fault_handler))
            .set_stack_index(DOUBLE_FAULT_IST_INDEX as u8);
        idt.set_handler(14, handler_with_error_code!(page_fault_handler));

        idt
    };
}

static TSS: Once<TaskStateSegment> = Once::new();
static GDT: Once<gdt::Gdt> = Once::new();
const DOUBLE_FAULT_IST_INDEX: usize = 0;

pub fn init(memory_controller: &mut MemoryController) {
    use x86::shared::segmentation::{SegmentSelector, set_cs};
    use x86::shared::task::load_tr;

    let double_fault_stack = memory_controller.alloc_stack(1)
        .expect("could not allocate double fault stack");

    let tss = TSS.call_once(|| {
        let mut tss = TaskStateSegment::new();
        tss.ist[DOUBLE_FAULT_IST_INDEX] = double_fault_stack.top() as u64;
        tss
    });

    let mut code_selector = SegmentSelector::empty();
    let mut tss_selector = SegmentSelector::empty();
    let gdt = GDT.call_once(|| {
        let mut gdt = gdt::Gdt::new();
        tss_selector = gdt.add_entry(gdt::Descriptor::tss_segment(&tss));
        code_selector = gdt.add_entry(gdt::Descriptor::kernel_code_segment());
        gdt
    });
    gdt.load();

    unsafe {
        set_cs(code_selector);
        load_tr(tss_selector);
    }

    IDT.load();
}

#[derive(Debug)]
#[repr(C)]
struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}

extern "C" fn divide_by_zero_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: DIVIDE BY ZERO\n{:#?}", stack_frame);
    loop {}
}

extern "C" fn breakpoint_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: BREAKPOINT at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
}

extern "C" fn invalid_opcode_handler(stack_frame: &ExceptionStackFrame) {
    println!("\nEXCEPTION: INVALID OPCODE at {:#x}\n{:#?}",
             stack_frame.instruction_pointer,
             stack_frame);
    loop {}
}

bitflags! {
    flags PageFaultErrorCode: u64 {
        const PROTECTION_VIOLATION = 1 << 0,
        const CAUSED_BY_WRITE = 1 << 1,
        const USER_MODE = 1 << 2,
        const MALFORMED_TABLE = 1 << 3,
        const INSTRUCTION_FETCH = 1 << 4,
    }
}

extern "C" fn page_fault_handler(stack_frame: &ExceptionStackFrame, error_code: u64) {
    use x86::shared::control_regs;
    println!("\nEXCEPTION: PAGE FAULT while accessing {:#x}\nerror code: \
                                  {:?}\n{:#?}",
             unsafe { control_regs::cr2() },
             PageFaultErrorCode::from_bits(error_code).unwrap(),
             stack_frame);
    loop {}
}

extern "C" fn double_fault_handler(stack_frame: &ExceptionStackFrame, _error_code: u64) {
    println!("\nEXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
    loop {}
}
<|endoftext|>


<commit_before>extern crate hamming as dna;

#[test]
fn test_no_difference_between_empty_strands() {
    assert_eq!(dna::hamming_distance("", "").unwrap(), 0);
}

#[test]
#[ignore]
fn test_no_difference_between_identical_strands() {
    assert_eq!(dna::hamming_distance("GGACTGA", "GGACTGA").unwrap(), 0);
}

#[test]
#[ignore]
fn test_complete_hamming_distance_in_small_strand() {
    assert_eq!(dna::hamming_distance("ACT", "GGA").unwrap(), 3);
}

#[test]
#[ignore]
fn test_small_hamming_distance_in_the_middle_somewhere() {
    assert_eq!(dna::hamming_distance("GGACG", "GGTCG").unwrap(), 1);
}

#[test]
#[ignore]
fn test_larger_distance() {
    assert_eq!(dna::hamming_distance("ACCAGGG", "ACTATGG").unwrap(), 2);
}

#[test]
#[ignore]
fn test_first_string_is_longer() {
    assert_eq!(dna::hamming_distance("AAA", "AA"), Result::Err("inputs of different length"));
}

#[test]
#[ignore]
fn test_second_string_is_longer() {
    assert_eq!(dna::hamming_distance("A", "AA"), Result::Err("inputs of different length"));
}
<commit_msg>Make error checking identical to other tests<commit_after>extern crate hamming as dna;

#[test]
fn test_no_difference_between_empty_strands() {
    assert_eq!(dna::hamming_distance("", "").unwrap(), 0);
}

#[test]
#[ignore]
fn test_no_difference_between_identical_strands() {
    assert_eq!(dna::hamming_distance("GGACTGA", "GGACTGA").unwrap(), 0);
}

#[test]
#[ignore]
fn test_complete_hamming_distance_in_small_strand() {
    assert_eq!(dna::hamming_distance("ACT", "GGA").unwrap(), 3);
}

#[test]
#[ignore]
fn test_small_hamming_distance_in_the_middle_somewhere() {
    assert_eq!(dna::hamming_distance("GGACG", "GGTCG").unwrap(), 1);
}

#[test]
#[ignore]
fn test_larger_distance() {
    assert_eq!(dna::hamming_distance("ACCAGGG", "ACTATGG").unwrap(), 2);
}

#[test]
#[ignore]
fn test_first_string_is_longer() {
    assert!(dna::hamming_distance("AAA", "AA").is_err());
}

#[test]
#[ignore]
fn test_second_string_is_longer() {
    assert!(dna::hamming_distance("A", "AA").is_err());
}
<|endoftext|>


<commit_before>use std::fmt::Write;

use hir::{
    AdtDef, Ty, FieldSource, source_binder,
    db::HirDatabase,
};
use ra_syntax::ast::{self, AstNode};

use crate::{AssistCtx, Assist};

pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?;

    // We already have some match arms, so we don't provide any assists.
    match match_expr.match_arm_list() {
        Some(arm_list) if arm_list.arms().count() > 0 => {
            return None;
        }
        _ => {}
    }

    let expr = match_expr.expr()?;
    let function =
        source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, expr.syntax())?;
    let infer_result = function.infer(ctx.db);
    let syntax_mapping = function.body_syntax_mapping(ctx.db);
    let node_expr = syntax_mapping.node_expr(expr)?;
    let match_expr_ty = infer_result[node_expr].clone();
    let enum_def = match match_expr_ty {
        Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
        Ty::Ref(adt, _) => match *adt {
            Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
            _ => return None,
        },
        _ => return None,
    };
    let enum_name = enum_def.name(ctx.db)?;
    let db = ctx.db;

    ctx.add_action("fill match arms", |edit| {
        let mut buf = format!("match {} {{\n", expr.syntax().text().to_string());
        let variants = enum_def.variants(db);
        for variant in variants {
            let name = match variant.name(db) {
                Some(it) => it,
                None => continue,
            };
            write!(&mut buf, "    {}::{}", enum_name, name.to_string()).unwrap();

            let pat = variant
                .fields(db)
                .into_iter()
                .map(|field| {
                    let name = field.name(db).to_string();
                    let (_, source) = field.source(db);
                    match source {
                        FieldSource::Named(_) => name,
                        FieldSource::Pos(_) => "_".to_string(),
                    }
                })
                .collect::<Vec<_>>();

            match pat.first().map(|s| s.as_str()) {
                Some("_") => write!(&mut buf, "({})", pat.join(", ")).unwrap(),
                Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).unwrap(),
                None => (),
            };

            buf.push_str(" => (),\n");
        }
        buf.push_str("}");
        edit.target(match_expr.syntax().range());
        edit.set_cursor(expr.syntax().range().start());
        edit.replace_node_and_indent(match_expr.syntax(), buf);
    });

    ctx.build()
}

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

    use super::fill_match_arms;

    #[test]
    fn fill_match_arms_empty_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match a<|> {}
            }
            "#,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match <|>a {
                    A::As => (),
                    A::Bs => (),
                    A::Cs(_) => (),
                    A::Ds(_, _) => (),
                    A::Es{x, y} => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn test_fill_match_arm_refs() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn foo(a: &A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn foo(a: &A) {
                match <|>a {
                    A::As => (),
                    A::Bs => (),
                    A::Cs(_) => (),
                    A::Ds(_, _) => (),
                    A::Es{x, y} => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match <|>a {
                    A::As => (),
                    A::Bs => (),
                    A::Cs(_) => (),
                    A::Ds(_, _) => (),
                    A::Es{x, y} => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match &E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>&E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_no_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_target() {
        check_assist_target(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|> {}
            }
            "#,
            "match E::X {}",
        );
    }
}
<commit_msg>Simplify test_fill_match_arm_refs test cases<commit_after>use std::fmt::Write;

use hir::{
    AdtDef, Ty, FieldSource, source_binder,
    db::HirDatabase,
};
use ra_syntax::ast::{self, AstNode};

use crate::{AssistCtx, Assist};

pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?;

    // We already have some match arms, so we don't provide any assists.
    match match_expr.match_arm_list() {
        Some(arm_list) if arm_list.arms().count() > 0 => {
            return None;
        }
        _ => {}
    }

    let expr = match_expr.expr()?;
    let function =
        source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, expr.syntax())?;
    let infer_result = function.infer(ctx.db);
    let syntax_mapping = function.body_syntax_mapping(ctx.db);
    let node_expr = syntax_mapping.node_expr(expr)?;
    let match_expr_ty = infer_result[node_expr].clone();
    let enum_def = match match_expr_ty {
        Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
        Ty::Ref(adt, _) => match *adt {
            Ty::Adt { def_id: AdtDef::Enum(e), .. } => e,
            _ => return None,
        },
        _ => return None,
    };
    let enum_name = enum_def.name(ctx.db)?;
    let db = ctx.db;

    ctx.add_action("fill match arms", |edit| {
        let mut buf = format!("match {} {{\n", expr.syntax().text().to_string());
        let variants = enum_def.variants(db);
        for variant in variants {
            let name = match variant.name(db) {
                Some(it) => it,
                None => continue,
            };
            write!(&mut buf, "    {}::{}", enum_name, name.to_string()).unwrap();

            let pat = variant
                .fields(db)
                .into_iter()
                .map(|field| {
                    let name = field.name(db).to_string();
                    let (_, source) = field.source(db);
                    match source {
                        FieldSource::Named(_) => name,
                        FieldSource::Pos(_) => "_".to_string(),
                    }
                })
                .collect::<Vec<_>>();

            match pat.first().map(|s| s.as_str()) {
                Some("_") => write!(&mut buf, "({})", pat.join(", ")).unwrap(),
                Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).unwrap(),
                None => (),
            };

            buf.push_str(" => (),\n");
        }
        buf.push_str("}");
        edit.target(match_expr.syntax().range());
        edit.set_cursor(expr.syntax().range().start());
        edit.replace_node_and_indent(match_expr.syntax(), buf);
    });

    ctx.build()
}

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

    use super::fill_match_arms;

    #[test]
    fn fill_match_arms_empty_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match a<|> {}
            }
            "#,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match <|>a {
                    A::As => (),
                    A::Bs => (),
                    A::Cs(_) => (),
                    A::Ds(_, _) => (),
                    A::Es{x, y} => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn test_fill_match_arm_refs() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
            }

            fn foo(a: &A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                As,
            }

            fn foo(a: &A) {
                match <|>a {
                    A::As => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum A {
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match <|>a {
                    A::Es{x, y} => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match &E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>&E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_no_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_target() {
        check_assist_target(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|> {}
            }
            "#,
            "match E::X {}",
        );
    }
}
<|endoftext|>


<commit_before>use super::*;

pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
    .union(paths::PATH_FIRST)
    .union(token_set![REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);

pub(super) fn pattern(p: &mut Parser) {
    pattern_r(p, PAT_RECOVERY_SET);
}

/// Parses a pattern list separated by pipes `|`
pub(super) fn pattern_list(p: &mut Parser) {
    pattern_list_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
    p.eat(T![|]);
    pattern_r(p, recovery_set);

    while p.eat(T![|]) {
        pattern_r(p, recovery_set);
    }
}

pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
    if let Some(lhs) = atom_pat(p, recovery_set) {
        // test range_pat
        // fn main() {
        //     match 92 {
        //         0 ... 100 => (),
        //         101 ..= 200 => (),
        //         200 .. 301=> (),
        //     }
        // }
        if p.at(T![...]) || p.at(T![..=]) || p.at(T![..]) {
            let m = lhs.precede(p);
            p.bump();
            atom_pat(p, recovery_set);
            m.complete(p, RANGE_PAT);
        }
        // test marco_pat
        // fn main() {
        //     let m!(x) = 0;
        // }
        else if lhs.kind() == PATH_PAT && p.at(T![!]) {
            let m = lhs.precede(p);
            items::macro_call_after_excl(p);
            m.complete(p, MACRO_CALL);
        }
    }
}

const PAT_RECOVERY_SET: TokenSet =
    token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];

fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
    let la0 = p.nth(0);
    let la1 = p.nth(1);
    if la0 == T![ref]
        || la0 == T![mut]
        || la0 == T![box]
        || (la0 == IDENT && !(la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!]))
    {
        return Some(bind_pat(p, true));
    }
    if paths::is_use_path_start(p) {
        return Some(path_pat(p));
    }

    if is_literal_pat_start(p) {
        return Some(literal_pat(p));
    }

    let m = match la0 {
        T![_] => placeholder_pat(p),
        T![&] => ref_pat(p),
        T!['('] => tuple_pat(p),
        T!['['] => slice_pat(p),
        _ => {
            p.err_recover("expected pattern", recovery_set);
            return None;
        }
    };
    Some(m)
}

fn is_literal_pat_start(p: &mut Parser) -> bool {
    p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
        || p.at_ts(expressions::LITERAL_FIRST)
}

// test literal_pattern
// fn main() {
//     match () {
//         -1 => (),
//         92 => (),
//         'c' => (),
//         "hello" => (),
//     }
// }
fn literal_pat(p: &mut Parser) -> CompletedMarker {
    assert!(is_literal_pat_start(p));
    let m = p.start();
    if p.at(T![-]) {
        p.bump();
    }
    expressions::literal(p);
    m.complete(p, LITERAL_PAT)
}

// test path_part
// fn foo() {
//     let foo::Bar = ();
//     let ::Bar = ();
//     let Bar { .. } = ();
//     let Bar(..) = ();
// }
fn path_pat(p: &mut Parser) -> CompletedMarker {
    assert!(paths::is_use_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    let kind = match p.current() {
        T!['('] => {
            tuple_pat_fields(p);
            TUPLE_STRUCT_PAT
        }
        T!['{'] => {
            field_pat_list(p);
            STRUCT_PAT
        }
        _ => PATH_PAT,
    };
    m.complete(p, kind)
}

// test tuple_pat_fields
// fn foo() {
//     let S() = ();
//     let S(_) = ();
//     let S(_,) = ();
//     let S(_, .. , x) = ();
// }
fn tuple_pat_fields(p: &mut Parser) {
    assert!(p.at(T!['(']));
    p.bump();
    pat_list(p, T![')']);
    p.expect(T![')']);
}

// test field_pat_list
// fn foo() {
//     let S {} = ();
//     let S { f, ref mut g } = ();
//     let S { h: _, ..} = ();
//     let S { h: _, } = ();
// }
fn field_pat_list(p: &mut Parser) {
    assert!(p.at(T!['{']));
    let m = p.start();
    p.bump();
    while !p.at(EOF) && !p.at(T!['}']) {
        match p.current() {
            T![..] => p.bump(),
            IDENT if p.nth(1) == T![:] => field_pat(p),
            T!['{'] => error_block(p, "expected ident"),
            _ => {
                bind_pat(p, false);
            }
        }
        if !p.at(T!['}']) {
            p.expect(T![,]);
        }
    }
    p.expect(T!['}']);
    m.complete(p, FIELD_PAT_LIST);
}

fn field_pat(p: &mut Parser) {
    assert!(p.at(IDENT));
    assert!(p.nth(1) == T![:]);

    let m = p.start();
    name(p);
    p.bump();
    pattern(p);
    m.complete(p, FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![_]));
    let m = p.start();
    p.bump();
    m.complete(p, PLACEHOLDER_PAT)
}

// test ref_pat
// fn main() {
//     let &a = ();
//     let &mut b = ();
// }
fn ref_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![&]));
    let m = p.start();
    p.bump();
    p.eat(T![mut]);
    pattern(p);
    m.complete(p, REF_PAT)
}

// test tuple_pat
// fn main() {
//     let (a, b, ..) = ();
// }
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['(']));
    let m = p.start();
    tuple_pat_fields(p);
    m.complete(p, TUPLE_PAT)
}

// test slice_pat
// fn main() {
//     let [a, b, ..] = [];
// }
fn slice_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['[']));
    let m = p.start();
    p.bump();
    pat_list(p, T![']']);
    p.expect(T![']']);
    m.complete(p, SLICE_PAT)
}

fn pat_list(p: &mut Parser, ket: SyntaxKind) {
    while !p.at(EOF) && !p.at(ket) {
        match p.current() {
            T![..] => p.bump(),
            _ => {
                if !p.at_ts(PATTERN_FIRST) {
                    p.error("expected a pattern");
                    break;
                }
                pattern(p)
            }
        }
        if !p.at(ket) {
            p.expect(T![,]);
        }
    }
}

// test bind_pat
// fn main() {
//     let a = ();
//     let mut b = ();
//     let ref c = ();
//     let ref mut d = ();
//     let e @ _ = ();
//     let ref mut f @ g @ _ = ();
//     let box i = Box::new(1i32);
// }
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
    let m = p.start();
    p.eat(T![box]);
    p.eat(T![ref]);
    p.eat(T![mut]);
    name(p);
    if with_at && p.eat(T![@]) {
        pattern(p);
    }
    m.complete(p, BIND_PAT)
}
<commit_msg>Add BOX_KW to PATTERN_FIRST<commit_after>use super::*;

pub(super) const PATTERN_FIRST: TokenSet = expressions::LITERAL_FIRST
    .union(paths::PATH_FIRST)
    .union(token_set![BOX_KW, REF_KW, MUT_KW, L_PAREN, L_BRACK, AMP, UNDERSCORE, MINUS]);

pub(super) fn pattern(p: &mut Parser) {
    pattern_r(p, PAT_RECOVERY_SET);
}

/// Parses a pattern list separated by pipes `|`
pub(super) fn pattern_list(p: &mut Parser) {
    pattern_list_r(p, PAT_RECOVERY_SET)
}

/// Parses a pattern list separated by pipes `|`
/// using the given `recovery_set`
pub(super) fn pattern_list_r(p: &mut Parser, recovery_set: TokenSet) {
    p.eat(T![|]);
    pattern_r(p, recovery_set);

    while p.eat(T![|]) {
        pattern_r(p, recovery_set);
    }
}

pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
    if let Some(lhs) = atom_pat(p, recovery_set) {
        // test range_pat
        // fn main() {
        //     match 92 {
        //         0 ... 100 => (),
        //         101 ..= 200 => (),
        //         200 .. 301=> (),
        //     }
        // }
        if p.at(T![...]) || p.at(T![..=]) || p.at(T![..]) {
            let m = lhs.precede(p);
            p.bump();
            atom_pat(p, recovery_set);
            m.complete(p, RANGE_PAT);
        }
        // test marco_pat
        // fn main() {
        //     let m!(x) = 0;
        // }
        else if lhs.kind() == PATH_PAT && p.at(T![!]) {
            let m = lhs.precede(p);
            items::macro_call_after_excl(p);
            m.complete(p, MACRO_CALL);
        }
    }
}

const PAT_RECOVERY_SET: TokenSet =
    token_set![LET_KW, IF_KW, WHILE_KW, LOOP_KW, MATCH_KW, R_PAREN, COMMA];

fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
    let la0 = p.nth(0);
    let la1 = p.nth(1);
    if la0 == T![ref]
        || la0 == T![mut]
        || la0 == T![box]
        || (la0 == IDENT && !(la1 == T![::] || la1 == T!['('] || la1 == T!['{'] || la1 == T![!]))
    {
        return Some(bind_pat(p, true));
    }
    if paths::is_use_path_start(p) {
        return Some(path_pat(p));
    }

    if is_literal_pat_start(p) {
        return Some(literal_pat(p));
    }

    let m = match la0 {
        T![_] => placeholder_pat(p),
        T![&] => ref_pat(p),
        T!['('] => tuple_pat(p),
        T!['['] => slice_pat(p),
        _ => {
            p.err_recover("expected pattern", recovery_set);
            return None;
        }
    };
    Some(m)
}

fn is_literal_pat_start(p: &mut Parser) -> bool {
    p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
        || p.at_ts(expressions::LITERAL_FIRST)
}

// test literal_pattern
// fn main() {
//     match () {
//         -1 => (),
//         92 => (),
//         'c' => (),
//         "hello" => (),
//     }
// }
fn literal_pat(p: &mut Parser) -> CompletedMarker {
    assert!(is_literal_pat_start(p));
    let m = p.start();
    if p.at(T![-]) {
        p.bump();
    }
    expressions::literal(p);
    m.complete(p, LITERAL_PAT)
}

// test path_part
// fn foo() {
//     let foo::Bar = ();
//     let ::Bar = ();
//     let Bar { .. } = ();
//     let Bar(..) = ();
// }
fn path_pat(p: &mut Parser) -> CompletedMarker {
    assert!(paths::is_use_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    let kind = match p.current() {
        T!['('] => {
            tuple_pat_fields(p);
            TUPLE_STRUCT_PAT
        }
        T!['{'] => {
            field_pat_list(p);
            STRUCT_PAT
        }
        _ => PATH_PAT,
    };
    m.complete(p, kind)
}

// test tuple_pat_fields
// fn foo() {
//     let S() = ();
//     let S(_) = ();
//     let S(_,) = ();
//     let S(_, .. , x) = ();
// }
fn tuple_pat_fields(p: &mut Parser) {
    assert!(p.at(T!['(']));
    p.bump();
    pat_list(p, T![')']);
    p.expect(T![')']);
}

// test field_pat_list
// fn foo() {
//     let S {} = ();
//     let S { f, ref mut g } = ();
//     let S { h: _, ..} = ();
//     let S { h: _, } = ();
// }
fn field_pat_list(p: &mut Parser) {
    assert!(p.at(T!['{']));
    let m = p.start();
    p.bump();
    while !p.at(EOF) && !p.at(T!['}']) {
        match p.current() {
            T![..] => p.bump(),
            IDENT if p.nth(1) == T![:] => field_pat(p),
            T!['{'] => error_block(p, "expected ident"),
            _ => {
                bind_pat(p, false);
            }
        }
        if !p.at(T!['}']) {
            p.expect(T![,]);
        }
    }
    p.expect(T!['}']);
    m.complete(p, FIELD_PAT_LIST);
}

fn field_pat(p: &mut Parser) {
    assert!(p.at(IDENT));
    assert!(p.nth(1) == T![:]);

    let m = p.start();
    name(p);
    p.bump();
    pattern(p);
    m.complete(p, FIELD_PAT);
}

// test placeholder_pat
// fn main() { let _ = (); }
fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![_]));
    let m = p.start();
    p.bump();
    m.complete(p, PLACEHOLDER_PAT)
}

// test ref_pat
// fn main() {
//     let &a = ();
//     let &mut b = ();
// }
fn ref_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T![&]));
    let m = p.start();
    p.bump();
    p.eat(T![mut]);
    pattern(p);
    m.complete(p, REF_PAT)
}

// test tuple_pat
// fn main() {
//     let (a, b, ..) = ();
// }
fn tuple_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['(']));
    let m = p.start();
    tuple_pat_fields(p);
    m.complete(p, TUPLE_PAT)
}

// test slice_pat
// fn main() {
//     let [a, b, ..] = [];
// }
fn slice_pat(p: &mut Parser) -> CompletedMarker {
    assert!(p.at(T!['[']));
    let m = p.start();
    p.bump();
    pat_list(p, T![']']);
    p.expect(T![']']);
    m.complete(p, SLICE_PAT)
}

fn pat_list(p: &mut Parser, ket: SyntaxKind) {
    while !p.at(EOF) && !p.at(ket) {
        match p.current() {
            T![..] => p.bump(),
            _ => {
                if !p.at_ts(PATTERN_FIRST) {
                    p.error("expected a pattern");
                    break;
                }
                pattern(p)
            }
        }
        if !p.at(ket) {
            p.expect(T![,]);
        }
    }
}

// test bind_pat
// fn main() {
//     let a = ();
//     let mut b = ();
//     let ref c = ();
//     let ref mut d = ();
//     let e @ _ = ();
//     let ref mut f @ g @ _ = ();
//     let box i = Box::new(1i32);
// }
fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
    let m = p.start();
    p.eat(T![box]);
    p.eat(T![ref]);
    p.eat(T![mut]);
    name(p);
    if with_at && p.eat(T![@]) {
        pattern(p);
    }
    m.complete(p, BIND_PAT)
}
<|endoftext|>