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

mod block;

use crate::{
    algo, ast, match_ast, AstNode, SyntaxError,
    SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
    SyntaxNode, SyntaxToken, TextSize, T,
};
use rowan::Direction;
use rustc_lexer::unescape::{
    self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode,
};
use std::convert::TryFrom;

fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str {
    use unescape::EscapeError as EE;

    #[rustfmt::skip]
    let err_message = match err {
        EE::ZeroChars => {
            "Literal must not be empty"
        }
        EE::MoreThanOneChar => {
            "Literal must be one character long"
        }
        EE::LoneSlash => {
            "Character must be escaped: `\\`"
        }
        EE::InvalidEscape => {
            "Invalid escape"
        }
        EE::BareCarriageReturn | EE::BareCarriageReturnInRawString => {
            "Character must be escaped: `\r`"
        }
        EE::EscapeOnlyChar => {
            "Escape character `\\` must be escaped itself"
        }
        EE::TooShortHexEscape => {
            "ASCII hex escape code must have exactly two digits"
        }
        EE::InvalidCharInHexEscape => {
            "ASCII hex escape code must contain only hex characters"
        }
        EE::OutOfRangeHexEscape => {
            "ASCII hex escape code must be at most 0x7F"
        }
        EE::NoBraceInUnicodeEscape => {
            "Missing `{` to begin the unicode escape"
        }
        EE::InvalidCharInUnicodeEscape => {
            "Unicode escape must contain only hex characters and underscores"
        }
        EE::EmptyUnicodeEscape => {
            "Unicode escape must not be empty"
        }
        EE::UnclosedUnicodeEscape => {
            "Missing `}` to terminate the unicode escape"
        }
        EE::LeadingUnderscoreUnicodeEscape => {
            "Unicode escape code must not begin with an underscore"
        }
        EE::OverlongUnicodeEscape => {
            "Unicode escape code must have at most 6 digits"
        }
        EE::LoneSurrogateUnicodeEscape => {
            "Unicode escape code must not be a surrogate"
        }
        EE::OutOfRangeUnicodeEscape => {
            "Unicode escape code must be at most 0x10FFFF"
        }
        EE::UnicodeEscapeInByte => {
            "Byte literals must not contain unicode escapes"
        }
        EE::NonAsciiCharInByte | EE::NonAsciiCharInByteString => {
            "Byte literals must not contain non-ASCII characters"
        }
    };

    err_message
}

pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
    // FIXME:
    // * Add unescape validation of raw string literals and raw byte string literals
    // * Add validation of doc comments are being attached to nodes

    let mut errors = Vec::new();
    for node in root.descendants() {
        match_ast! {
            match node {
                ast::Literal(it) => validate_literal(it, &mut errors),
                ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
                ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
                ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
                ast::Visibility(it) => validate_visibility(it, &mut errors),
                ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
                ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
                ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
                ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
                ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
                _ => (),
            }
        }
    }
    errors
}

fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
    // FIXME: move this function to outer scope (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366196658)
    fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> {
        text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end))
    }

    let token = literal.token();
    let text = token.text().as_str();

    // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205)
    let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| {
        let off = token.text_range().start() + TextSize::try_from(off + prefix_len).unwrap();
        acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
    };

    match literal.kind() {
        ast::LiteralKind::String(s) => {
            if !s.is_raw() {
                if let Some(without_quotes) = unquote(text, 1, '"') {
                    unescape_literal(without_quotes, Mode::Str, &mut |range, char| {
                        if let Err(err) = char {
                            push_err(1, (range.start, err));
                        }
                    })
                }
            }
        }
        ast::LiteralKind::ByteString(s) => {
            if !s.is_raw() {
                if let Some(without_quotes) = unquote(text, 2, '"') {
                    unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
                        if let Err(err) = char {
                            push_err(2, (range.start, err));
                        }
                    })
                }
            }
        }
        ast::LiteralKind::Char => {
            if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
                push_err(1, e);
            }
        }
        ast::LiteralKind::Byte => {
            if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
                push_err(2, e);
            }
        }
        ast::LiteralKind::IntNumber(_)
        | ast::LiteralKind::FloatNumber(_)
        | ast::LiteralKind::Bool(_) => {}
    }
}

pub(crate) fn validate_block_structure(root: &SyntaxNode) {
    let mut stack = Vec::new();
    for node in root.descendants() {
        match node.kind() {
            T!['{'] => stack.push(node),
            T!['}'] => {
                if let Some(pair) = stack.pop() {
                    assert_eq!(
                        node.parent(),
                        pair.parent(),
                        "\nunpaired curleys:\n{}\n{:#?}\n",
                        root.text(),
                        root,
                    );
                    assert!(
                        node.next_sibling().is_none() && pair.prev_sibling().is_none(),
                        "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
                        node,
                        root.text(),
                        node.text(),
                    );
                }
            }
            _ => (),
        }
    }
}

fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<SyntaxError>) {
    if let Some(int_token) = int_token(name_ref) {
        if int_token.text().chars().any(|c| !c.is_digit(10)) {
            errors.push(SyntaxError::new(
                "Tuple (struct) field access is only allowed through \
                decimal integers with no underscores or suffix",
                int_token.text_range(),
            ));
        }
    }

    fn int_token(name_ref: Option<ast::NameRef>) -> Option<SyntaxToken> {
        name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER)
    }
}

fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
    let parent = match vis.syntax().parent() {
        Some(it) => it,
        None => return,
    };
    match parent.kind() {
        FN | CONST | TYPE_ALIAS => (),
        _ => return,
    }

    let impl_def = match parent.parent().and_then(|it| it.parent()).and_then(ast::Impl::cast) {
        Some(it) => it,
        None => return,
    };
    if impl_def.trait_().is_some() {
        errors.push(SyntaxError::new("Unnecessary visibility qualifier", vis.syntax.text_range()));
    }
}

fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
    if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() {
        errors.push(SyntaxError::new(
            "An inclusive range must have an end expression",
            expr.syntax().text_range(),
        ));
    }
}

fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxError>) {
    use ast::PathSegmentKind;

    let path = segment.parent_path();
    let is_path_start = segment.coloncolon_token().is_none() && path.qualifier().is_none();

    if let Some(token) = segment.self_token() {
        if !is_path_start {
            errors.push(SyntaxError::new(
                "The `self` keyword is only allowed as the first segment of a path",
                token.text_range(),
            ));
        }
    } else if let Some(token) = segment.crate_token() {
        if !is_path_start || use_prefix(path).is_some() {
            errors.push(SyntaxError::new(
                "The `crate` keyword is only allowed as the first segment of a path",
                token.text_range(),
            ));
        }
    } else if let Some(token) = segment.super_token() {
        if !all_supers(&path) {
            errors.push(SyntaxError::new(
                "The `super` keyword may only be preceded by other `super`s",
                token.text_range(),
            ));
            return;
        }

        let mut curr_path = path;
        while let Some(prefix) = use_prefix(curr_path) {
            if !all_supers(&prefix) {
                errors.push(SyntaxError::new(
                    "The `super` keyword may only be preceded by other `super`s",
                    token.text_range(),
                ));
                return;
            }
            curr_path = prefix;
        }
    }

    fn use_prefix(mut path: ast::Path) -> Option<ast::Path> {
        for node in path.syntax().ancestors().skip(1) {
            match_ast! {
                match node {
                    ast::UseTree(it) => if let Some(tree_path) = it.path() {
                        // Even a top-level path exists within a `UseTree` so we must explicitly
                        // allow our path but disallow anything else
                        if tree_path != path {
                            return Some(tree_path);
                        }
                    },
                    ast::UseTreeList(_it) => continue,
                    ast::Path(parent) => path = parent,
                    _ => return None,
                }
            };
        }
        return None;
    }

    fn all_supers(path: &ast::Path) -> bool {
        let segment = match path.segment() {
            Some(it) => it,
            None => return false,
        };

        if segment.kind() != Some(PathSegmentKind::SuperKw) {
            return false;
        }

        if let Some(ref subpath) = path.qualifier() {
            return all_supers(subpath);
        }

        return true;
    }
}

fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) {
    if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
        if let Some(err) = validate_trait_object_ty(ty) {
            errors.push(err);
        }
    }
}

fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) {
    if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
        if let Some(err) = validate_trait_object_ty(ty) {
            errors.push(err);
        }
    }
}

fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) {
    if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) {
        if let Some(err) = validate_trait_object_ty(ty) {
            errors.push(err);
        }
    }
}

fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
    let tbl = ty.type_bound_list()?;

    if tbl.bounds().count() > 1 {
        let dyn_token = ty.dyn_token()?;
        let potential_parentheses =
            algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
        let kind = potential_parentheses.kind();
        if !matches!(kind, T!['('] | T![<] | T![=]) {
            return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
        }
    }
    None
}
<commit_msg>Reject visibilities on `macro_rules!`<commit_after>//! FIXME: write short doc here

mod block;

use crate::{
    algo,
    ast::{self, VisibilityOwner},
    match_ast, AstNode, SyntaxError,
    SyntaxKind::{CONST, FN, INT_NUMBER, TYPE_ALIAS},
    SyntaxNode, SyntaxToken, TextSize, T,
};
use rowan::Direction;
use rustc_lexer::unescape::{
    self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode,
};
use std::convert::TryFrom;

fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str {
    use unescape::EscapeError as EE;

    #[rustfmt::skip]
    let err_message = match err {
        EE::ZeroChars => {
            "Literal must not be empty"
        }
        EE::MoreThanOneChar => {
            "Literal must be one character long"
        }
        EE::LoneSlash => {
            "Character must be escaped: `\\`"
        }
        EE::InvalidEscape => {
            "Invalid escape"
        }
        EE::BareCarriageReturn | EE::BareCarriageReturnInRawString => {
            "Character must be escaped: `\r`"
        }
        EE::EscapeOnlyChar => {
            "Escape character `\\` must be escaped itself"
        }
        EE::TooShortHexEscape => {
            "ASCII hex escape code must have exactly two digits"
        }
        EE::InvalidCharInHexEscape => {
            "ASCII hex escape code must contain only hex characters"
        }
        EE::OutOfRangeHexEscape => {
            "ASCII hex escape code must be at most 0x7F"
        }
        EE::NoBraceInUnicodeEscape => {
            "Missing `{` to begin the unicode escape"
        }
        EE::InvalidCharInUnicodeEscape => {
            "Unicode escape must contain only hex characters and underscores"
        }
        EE::EmptyUnicodeEscape => {
            "Unicode escape must not be empty"
        }
        EE::UnclosedUnicodeEscape => {
            "Missing `}` to terminate the unicode escape"
        }
        EE::LeadingUnderscoreUnicodeEscape => {
            "Unicode escape code must not begin with an underscore"
        }
        EE::OverlongUnicodeEscape => {
            "Unicode escape code must have at most 6 digits"
        }
        EE::LoneSurrogateUnicodeEscape => {
            "Unicode escape code must not be a surrogate"
        }
        EE::OutOfRangeUnicodeEscape => {
            "Unicode escape code must be at most 0x10FFFF"
        }
        EE::UnicodeEscapeInByte => {
            "Byte literals must not contain unicode escapes"
        }
        EE::NonAsciiCharInByte | EE::NonAsciiCharInByteString => {
            "Byte literals must not contain non-ASCII characters"
        }
    };

    err_message
}

pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
    // FIXME:
    // * Add unescape validation of raw string literals and raw byte string literals
    // * Add validation of doc comments are being attached to nodes

    let mut errors = Vec::new();
    for node in root.descendants() {
        match_ast! {
            match node {
                ast::Literal(it) => validate_literal(it, &mut errors),
                ast::BlockExpr(it) => block::validate_block_expr(it, &mut errors),
                ast::FieldExpr(it) => validate_numeric_name(it.name_ref(), &mut errors),
                ast::RecordExprField(it) => validate_numeric_name(it.name_ref(), &mut errors),
                ast::Visibility(it) => validate_visibility(it, &mut errors),
                ast::RangeExpr(it) => validate_range_expr(it, &mut errors),
                ast::PathSegment(it) => validate_path_keywords(it, &mut errors),
                ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors),
                ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors),
                ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors),
                ast::MacroRules(it) => validate_macro_rules(it, &mut errors),
                _ => (),
            }
        }
    }
    errors
}

fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
    // FIXME: move this function to outer scope (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366196658)
    fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> {
        text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end))
    }

    let token = literal.token();
    let text = token.text().as_str();

    // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205)
    let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| {
        let off = token.text_range().start() + TextSize::try_from(off + prefix_len).unwrap();
        acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
    };

    match literal.kind() {
        ast::LiteralKind::String(s) => {
            if !s.is_raw() {
                if let Some(without_quotes) = unquote(text, 1, '"') {
                    unescape_literal(without_quotes, Mode::Str, &mut |range, char| {
                        if let Err(err) = char {
                            push_err(1, (range.start, err));
                        }
                    })
                }
            }
        }
        ast::LiteralKind::ByteString(s) => {
            if !s.is_raw() {
                if let Some(without_quotes) = unquote(text, 2, '"') {
                    unescape_byte_literal(without_quotes, Mode::ByteStr, &mut |range, char| {
                        if let Err(err) = char {
                            push_err(2, (range.start, err));
                        }
                    })
                }
            }
        }
        ast::LiteralKind::Char => {
            if let Some(Err(e)) = unquote(text, 1, '\'').map(unescape_char) {
                push_err(1, e);
            }
        }
        ast::LiteralKind::Byte => {
            if let Some(Err(e)) = unquote(text, 2, '\'').map(unescape_byte) {
                push_err(2, e);
            }
        }
        ast::LiteralKind::IntNumber(_)
        | ast::LiteralKind::FloatNumber(_)
        | ast::LiteralKind::Bool(_) => {}
    }
}

pub(crate) fn validate_block_structure(root: &SyntaxNode) {
    let mut stack = Vec::new();
    for node in root.descendants() {
        match node.kind() {
            T!['{'] => stack.push(node),
            T!['}'] => {
                if let Some(pair) = stack.pop() {
                    assert_eq!(
                        node.parent(),
                        pair.parent(),
                        "\nunpaired curleys:\n{}\n{:#?}\n",
                        root.text(),
                        root,
                    );
                    assert!(
                        node.next_sibling().is_none() && pair.prev_sibling().is_none(),
                        "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
                        node,
                        root.text(),
                        node.text(),
                    );
                }
            }
            _ => (),
        }
    }
}

fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<SyntaxError>) {
    if let Some(int_token) = int_token(name_ref) {
        if int_token.text().chars().any(|c| !c.is_digit(10)) {
            errors.push(SyntaxError::new(
                "Tuple (struct) field access is only allowed through \
                decimal integers with no underscores or suffix",
                int_token.text_range(),
            ));
        }
    }

    fn int_token(name_ref: Option<ast::NameRef>) -> Option<SyntaxToken> {
        name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER)
    }
}

fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
    let parent = match vis.syntax().parent() {
        Some(it) => it,
        None => return,
    };
    match parent.kind() {
        FN | CONST | TYPE_ALIAS => (),
        _ => return,
    }

    let impl_def = match parent.parent().and_then(|it| it.parent()).and_then(ast::Impl::cast) {
        Some(it) => it,
        None => return,
    };
    if impl_def.trait_().is_some() {
        errors.push(SyntaxError::new("Unnecessary visibility qualifier", vis.syntax.text_range()));
    }
}

fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
    if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() {
        errors.push(SyntaxError::new(
            "An inclusive range must have an end expression",
            expr.syntax().text_range(),
        ));
    }
}

fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxError>) {
    use ast::PathSegmentKind;

    let path = segment.parent_path();
    let is_path_start = segment.coloncolon_token().is_none() && path.qualifier().is_none();

    if let Some(token) = segment.self_token() {
        if !is_path_start {
            errors.push(SyntaxError::new(
                "The `self` keyword is only allowed as the first segment of a path",
                token.text_range(),
            ));
        }
    } else if let Some(token) = segment.crate_token() {
        if !is_path_start || use_prefix(path).is_some() {
            errors.push(SyntaxError::new(
                "The `crate` keyword is only allowed as the first segment of a path",
                token.text_range(),
            ));
        }
    } else if let Some(token) = segment.super_token() {
        if !all_supers(&path) {
            errors.push(SyntaxError::new(
                "The `super` keyword may only be preceded by other `super`s",
                token.text_range(),
            ));
            return;
        }

        let mut curr_path = path;
        while let Some(prefix) = use_prefix(curr_path) {
            if !all_supers(&prefix) {
                errors.push(SyntaxError::new(
                    "The `super` keyword may only be preceded by other `super`s",
                    token.text_range(),
                ));
                return;
            }
            curr_path = prefix;
        }
    }

    fn use_prefix(mut path: ast::Path) -> Option<ast::Path> {
        for node in path.syntax().ancestors().skip(1) {
            match_ast! {
                match node {
                    ast::UseTree(it) => if let Some(tree_path) = it.path() {
                        // Even a top-level path exists within a `UseTree` so we must explicitly
                        // allow our path but disallow anything else
                        if tree_path != path {
                            return Some(tree_path);
                        }
                    },
                    ast::UseTreeList(_it) => continue,
                    ast::Path(parent) => path = parent,
                    _ => return None,
                }
            };
        }
        return None;
    }

    fn all_supers(path: &ast::Path) -> bool {
        let segment = match path.segment() {
            Some(it) => it,
            None => return false,
        };

        if segment.kind() != Some(PathSegmentKind::SuperKw) {
            return false;
        }

        if let Some(ref subpath) = path.qualifier() {
            return all_supers(subpath);
        }

        return true;
    }
}

fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) {
    if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
        if let Some(err) = validate_trait_object_ty(ty) {
            errors.push(err);
        }
    }
}

fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) {
    if let Some(ast::Type::DynTraitType(ty)) = ty.ty() {
        if let Some(err) = validate_trait_object_ty(ty) {
            errors.push(err);
        }
    }
}

fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) {
    if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) {
        if let Some(err) = validate_trait_object_ty(ty) {
            errors.push(err);
        }
    }
}

fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> {
    let tbl = ty.type_bound_list()?;

    if tbl.bounds().count() > 1 {
        let dyn_token = ty.dyn_token()?;
        let potential_parentheses =
            algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?;
        let kind = potential_parentheses.kind();
        if !matches!(kind, T!['('] | T![<] | T![=]) {
            return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range()));
        }
    }
    None
}

fn validate_macro_rules(mac: ast::MacroRules, errors: &mut Vec<SyntaxError>) {
    if let Some(vis) = mac.visibility() {
        errors.push(SyntaxError::new(
            "visibilities are not allowed on `macro_rules!` items",
            vis.syntax().text_range(),
        ));
    }
}
<|endoftext|>


<commit_before>use super::Command;

extern crate chrono;

use lib::fs::*;
use lib::setting::*;
use self::chrono::Local;
use std::fs;
use std::path::PathBuf;

pub struct Sweep;

impl Command for Sweep {
    fn validation(&self) -> bool { true }

    fn help_message(&self) -> &'static str {
        return "sweep!";
    }

    fn main(&self) {
        println!("Sweep ...");

        let now  = Local::now();
        let date = format!("{}", now.format("%Y-%m-%d"));

        let path_to_dust_box = path_buf![storage_dir(), date, "dust"];
        create_essential_dir(&path_to_dust_box);

        let ignore = read_ignore_file();

        let target_files = walk_dir(".")
            .difference(&ignore)
            .cloned()
            .collect::<Vec<String>>();

        for target in target_files.iter() {
            let target_path = path_buf![&target];
            let target_name = extract_file_name(&target_path);
            let target_base = extract_base(&target_path);
            let to          = path_buf![&path_to_dust_box, target_base];

            match fs::create_dir_all(&to) {
                Ok(_)    => println!("OK: Created {:?} directory.", to),
                Err(why) => panic!("ERROR: {}", why),
            }

            // forcedly overwrite if the file exists with same name.
            match fs::rename(target, path_buf![to, target_name]) {
                Ok(_)    => println!("OK: Moved {:?} to {:?}", target, path_to_dust_box),
                Err(why) => panic!("ERROR: {}", why),
            }
        }

        // delete all empty directories.
    }
}
<commit_msg>Fix as enabling to create "dust" dir<commit_after>use super::Command;

extern crate chrono;

use lib::fs::*;
use lib::setting::*;
use self::chrono::Local;
use std::fs;
use std::path::PathBuf;

pub struct Sweep;

impl Command for Sweep {
    fn validation(&self) -> bool { true }

    fn help_message(&self) -> &'static str {
        return "sweep!";
    }

    fn main(&self) {
        println!("Sweep ...");

        let now  = Local::now();
        let date = format!("{}", now.format("%Y-%m-%d"));

        let path_to_dust_box = path_buf![storage_dir(), date, "dust"];
        match fs::create_dir_all(&path_to_dust_box) {
            Ok(_)    => println!("OK: Created {:?} directory.", path_to_dust_box),
            Err(why) => panic!("ERROR: {}", why),
        }

        let ignore = read_ignore_file();

        let target_files = walk_dir(".")
            .difference(&ignore)
            .cloned()
            .collect::<Vec<String>>();

        for target in target_files.iter() {
            let target_path = path_buf![&target];
            let target_name = extract_file_name(&target_path);
            let target_base = extract_base(&target_path);
            let to          = path_buf![&path_to_dust_box, target_base];

            match fs::create_dir_all(&to) {
                Ok(_)    => println!("OK: Created {:?} directory.", to),
                Err(why) => panic!("ERROR: {}", why),
            }

            // forcedly overwrite if the file exists with same name.
            match fs::rename(target, path_buf![to, target_name]) {
                Ok(_)    => println!("OK: Moved {:?} to {:?}", target, path_to_dust_box),
                Err(why) => panic!("ERROR: {}", why),
            }
        }

        // delete all empty directories.
    }
}
<|endoftext|>


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

//! CSS table formatting contexts.

#![deny(unsafe_code)]

use app_units::Au;
use context::LayoutContext;
use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
use layout_debug;
use std::cmp::max;
use std::fmt;
use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues;
use style::values::computed::LengthOrPercentageOrAuto;

/// A table formatting context.
pub struct TableColGroupFlow {
    /// Data common to all flows.
    pub base: BaseFlow,

    /// The associated fragment.
    pub fragment: Option<Fragment>,

    /// The table column fragments
    pub cols: Vec<Fragment>,

    /// The specified inline-sizes of table columns. (We use `LengthOrPercentageOrAuto` here in
    /// lieu of `ColumnInlineSize` because column groups do not establish minimum or preferred
    /// inline sizes.)
    pub inline_sizes: Vec<LengthOrPercentageOrAuto>,
}

impl TableColGroupFlow {
    pub fn from_fragments(fragment: Fragment, fragments: Vec<Fragment>) -> TableColGroupFlow {
        let writing_mode = fragment.style().writing_mode;
        TableColGroupFlow {
            base: BaseFlow::new(Some(fragment.style()),
                                writing_mode,
                                ForceNonfloatedFlag::ForceNonfloated),
            fragment: Some(fragment),
            cols: fragments,
            inline_sizes: vec!(),
        }
    }
}

impl Flow for TableColGroupFlow {
    fn class(&self) -> FlowClass {
        FlowClass::TableColGroup
    }

    fn as_mut_table_colgroup(&mut self) -> &mut TableColGroupFlow {
        self
    }

    fn bubble_inline_sizes(&mut self) {
        let _scope = layout_debug_scope!("table_colgroup::bubble_inline_sizes {:x}",
                                            self.base.debug_id());

        for fragment in &self.cols {
            // Retrieve the specified value from the appropriate CSS property.
            let inline_size = fragment.style().content_inline_size();
            let span = match fragment.specific {
                SpecificFragmentInfo::TableColumn(col_fragment) => max(col_fragment.span, 1),
                _ => panic!("non-table-column fragment inside table column?!"),
            };
            for _ in 0..span {
                self.inline_sizes.push(inline_size)
            }
        }
    }

    /// Table column inline-sizes are assigned in the table flow and propagated to table row flows
    /// and/or rowgroup flows. Therefore, table colgroup flows do not need to assign inline-sizes.
    fn assign_inline_sizes(&mut self, _: &LayoutContext) {
    }

    /// Table columns do not have block-size.
    fn assign_block_size(&mut self, _: &LayoutContext) {
    }

    fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}

    fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}

    // Table columns are invisible.
    fn build_display_list(&mut self, _: &mut DisplayListBuildState) { }

    fn collect_stacking_contexts(&mut self, _: &mut DisplayListBuildState) {}

    fn repair_style(&mut self, _: &::ServoArc<ComputedValues>) {}

    fn compute_overflow(&self) -> Overflow {
        Overflow::new()
    }

    fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au> {
        panic!("Table column groups can't be containing blocks!")
    }

    fn iterate_through_fragment_border_boxes(&self,
                                             _: &mut FragmentBorderBoxIterator,
                                             _: i32,
                                             _: &Point2D<Au>) {}

    fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {}
}

impl fmt::Debug for TableColGroupFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.fragment {
            Some(ref rb) => write!(f, "TableColGroupFlow: {:?}", rb),
            None => write!(f, "TableColGroupFlow"),
        }
    }
}
<commit_msg>Fix warning in scroll root id assignment to TableColGroupFlow<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! CSS table formatting contexts.

#![deny(unsafe_code)]

use app_units::Au;
use context::LayoutContext;
use display_list_builder::DisplayListBuildState;
use euclid::Point2D;
use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
use layout_debug;
use std::cmp::max;
use std::fmt;
use style::logical_geometry::LogicalSize;
use style::properties::ComputedValues;
use style::values::computed::LengthOrPercentageOrAuto;

/// A table formatting context.
pub struct TableColGroupFlow {
    /// Data common to all flows.
    pub base: BaseFlow,

    /// The associated fragment.
    pub fragment: Option<Fragment>,

    /// The table column fragments
    pub cols: Vec<Fragment>,

    /// The specified inline-sizes of table columns. (We use `LengthOrPercentageOrAuto` here in
    /// lieu of `ColumnInlineSize` because column groups do not establish minimum or preferred
    /// inline sizes.)
    pub inline_sizes: Vec<LengthOrPercentageOrAuto>,
}

impl TableColGroupFlow {
    pub fn from_fragments(fragment: Fragment, fragments: Vec<Fragment>) -> TableColGroupFlow {
        let writing_mode = fragment.style().writing_mode;
        TableColGroupFlow {
            base: BaseFlow::new(Some(fragment.style()),
                                writing_mode,
                                ForceNonfloatedFlag::ForceNonfloated),
            fragment: Some(fragment),
            cols: fragments,
            inline_sizes: vec!(),
        }
    }
}

impl Flow for TableColGroupFlow {
    fn class(&self) -> FlowClass {
        FlowClass::TableColGroup
    }

    fn as_mut_table_colgroup(&mut self) -> &mut TableColGroupFlow {
        self
    }

    fn bubble_inline_sizes(&mut self) {
        let _scope = layout_debug_scope!("table_colgroup::bubble_inline_sizes {:x}",
                                            self.base.debug_id());

        for fragment in &self.cols {
            // Retrieve the specified value from the appropriate CSS property.
            let inline_size = fragment.style().content_inline_size();
            let span = match fragment.specific {
                SpecificFragmentInfo::TableColumn(col_fragment) => max(col_fragment.span, 1),
                _ => panic!("non-table-column fragment inside table column?!"),
            };
            for _ in 0..span {
                self.inline_sizes.push(inline_size)
            }
        }
    }

    /// Table column inline-sizes are assigned in the table flow and propagated to table row flows
    /// and/or rowgroup flows. Therefore, table colgroup flows do not need to assign inline-sizes.
    fn assign_inline_sizes(&mut self, _: &LayoutContext) {
    }

    /// Table columns do not have block-size.
    fn assign_block_size(&mut self, _: &LayoutContext) {
    }

    fn update_late_computed_inline_position_if_necessary(&mut self, _: Au) {}

    fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}

    // Table columns are invisible.
    fn build_display_list(&mut self, _: &mut DisplayListBuildState) { }

    fn collect_stacking_contexts(&mut self, state: &mut DisplayListBuildState) {
        self.base.stacking_context_id = state.current_stacking_context_id;
        self.base.scroll_root_id = Some(state.current_scroll_root_id);
    }

    fn repair_style(&mut self, _: &::ServoArc<ComputedValues>) {}

    fn compute_overflow(&self) -> Overflow {
        Overflow::new()
    }

    fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au> {
        panic!("Table column groups can't be containing blocks!")
    }

    fn iterate_through_fragment_border_boxes(&self,
                                             _: &mut FragmentBorderBoxIterator,
                                             _: i32,
                                             _: &Point2D<Au>) {}

    fn mutate_fragments(&mut self, _: &mut FnMut(&mut Fragment)) {}
}

impl fmt::Debug for TableColGroupFlow {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.fragment {
            Some(ref rb) => write!(f, "TableColGroupFlow: {:?}", rb),
            None => write!(f, "TableColGroupFlow"),
        }
    }
}
<|endoftext|>


<commit_before>//! Mutate a program
//!
//! Mutation is a source of change in a population. Sometimes mutations are
//! beneficial and improve the overall fitness.

use rand;
use rand::distributions::{IndependentSample, Range};
use super::super::grammar::Program;

/// Determines if a mutation should occur
pub trait MutateDecision {
    /// Returns true when a mutation should occur, false otherwise
    fn should_mutate(&mut self) -> bool;
}

/// A MutateDecision that decides randomly
pub struct RandomDecision {
    rng: Box<rand::Rng>,
    range: Range<f32>,
    threshold: f32,
}

impl RandomDecision {
    /// Creates a RandomDecision with a fixed threshold
    pub fn new(threshold: f32) -> RandomDecision {
        RandomDecision {
            rng: Box::new(rand::thread_rng()),
            range: Range::new(0f32, 1.0),
            threshold: threshold,
        }
    }
}

impl MutateDecision for RandomDecision {
    fn should_mutate(&mut self) -> bool {
        self.range.ind_sample(&mut self.rng) < self.threshold
    }
}

/// Somethings can mutate
pub trait Mutatable {
    /// Returns a mutated variant of self
    fn mutate(&self, decide: &mut MutateDecision) -> Self;
}

impl Mutatable for Program {
    fn mutate(&self, mut decide: &mut MutateDecision) -> Program {
        match *self {
            Program::Forward(ref contained_program) => {
                if decide.should_mutate() {
                    Program::Backward(Box::new(contained_program.mutate(decide)))
                } else {
                    Program::Forward(Box::new(contained_program.mutate(decide)))
                }
            },
            Program::Backward(ref contained_program) => {
                if decide.should_mutate() {
                    Program::Forward(Box::new(contained_program.mutate(decide)))
                } else {
                    Program::Backward(Box::new(contained_program.mutate(decide)))
                }
            },
            Program::Stop => Program::Stop,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::grammar::Program;
    use super::*;

    enum TestDecision {
        AlwaysMutate,
        NeverMutate,
    }

    impl MutateDecision for TestDecision {
        fn should_mutate(&mut self) -> bool {
            match *self {
                TestDecision::AlwaysMutate => true,
                TestDecision::NeverMutate => false,
            }
        }
    }

    #[test]
    fn should_never_mutate() {
        let program: Program = Program::Forward(Box::new(Program::Stop));
        let decision: TestDecision = TestDecision::NeverMutate;

        let mutation = program.mutate(Box::new(decision));

        assert_eq!(mutation, Program::Forward(Box::new(Program::Stop)));

    }

    #[test]
    fn should_always_mutate() {
        let program: Program = Program::Forward(Box::new(Program::Stop));
        let decision: TestDecision = TestDecision::AlwaysMutate;

        let mutation = program.mutate(Box::new(decision));

        assert_eq!(mutation, Program::Backward(Box::new(Program::Stop)));

    }
}
<commit_msg>Forgot to update test to new uses<commit_after>//! Mutate a program
//!
//! Mutation is a source of change in a population. Sometimes mutations are
//! beneficial and improve the overall fitness.

use rand;
use rand::distributions::{IndependentSample, Range};
use super::super::grammar::Program;

/// Determines if a mutation should occur
pub trait MutateDecision {
    /// Returns true when a mutation should occur, false otherwise
    fn should_mutate(&mut self) -> bool;
}

/// A MutateDecision that decides randomly
pub struct RandomDecision {
    rng: Box<rand::Rng>,
    range: Range<f32>,
    threshold: f32,
}

impl RandomDecision {
    /// Creates a RandomDecision with a fixed threshold
    pub fn new(threshold: f32) -> RandomDecision {
        RandomDecision {
            rng: Box::new(rand::thread_rng()),
            range: Range::new(0f32, 1.0),
            threshold: threshold,
        }
    }
}

impl MutateDecision for RandomDecision {
    fn should_mutate(&mut self) -> bool {
        self.range.ind_sample(&mut self.rng) < self.threshold
    }
}

/// Somethings can mutate
pub trait Mutatable {
    /// Returns a mutated variant of self
    fn mutate(&self, decide: &mut MutateDecision) -> Self;
}

impl Mutatable for Program {
    fn mutate(&self, mut decide: &mut MutateDecision) -> Program {
        match *self {
            Program::Forward(ref contained_program) => {
                if decide.should_mutate() {
                    Program::Backward(Box::new(contained_program.mutate(decide)))
                } else {
                    Program::Forward(Box::new(contained_program.mutate(decide)))
                }
            },
            Program::Backward(ref contained_program) => {
                if decide.should_mutate() {
                    Program::Forward(Box::new(contained_program.mutate(decide)))
                } else {
                    Program::Backward(Box::new(contained_program.mutate(decide)))
                }
            },
            Program::Stop => Program::Stop,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::super::grammar::Program;
    use super::*;

    enum TestDecision {
        AlwaysMutate,
        NeverMutate,
    }

    impl MutateDecision for TestDecision {
        fn should_mutate(&mut self) -> bool {
            match *self {
                TestDecision::AlwaysMutate => true,
                TestDecision::NeverMutate => false,
            }
        }
    }

    #[test]
    fn should_never_mutate() {
        let program: Program = Program::Forward(Box::new(Program::Stop));
        let mut decision: TestDecision = TestDecision::NeverMutate;

        let mutation = program.mutate(&mut decision);

        assert_eq!(mutation, Program::Forward(Box::new(Program::Stop)));

    }

    #[test]
    fn should_always_mutate() {
        let program: Program = Program::Forward(Box::new(Program::Stop));
        let mut decision: TestDecision = TestDecision::AlwaysMutate;

        let mutation = program.mutate(&mut decision);

        assert_eq!(mutation, Program::Backward(Box::new(Program::Stop)));

    }
}
<|endoftext|>


<commit_before>//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
use rustc_hash::FxHashMap;

use hir::{HirDisplay, PathResolution, SemanticsScope};
use syntax::{
    algo::SyntaxRewriter,
    ast::{self, AstNode},
};

pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
    SyntaxRewriter::from_fn(|element| match element {
        syntax::SyntaxElement::Node(n) => {
            let replacement = transformer.get_substitution(&n)?;
            Some(replacement.into())
        }
        _ => None,
    })
    .rewrite_ast(&node)
}

pub trait AstTransform<'a> {
    fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode>;

    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a>;
    fn or<T: AstTransform<'a> + 'a>(self, other: T) -> Box<dyn AstTransform<'a> + 'a>
    where
        Self: Sized + 'a,
    {
        self.chain_before(Box::new(other))
    }
}

struct NullTransformer;

impl<'a> AstTransform<'a> for NullTransformer {
    fn get_substitution(&self, _node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        None
    }
    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
        other
    }
}

pub struct SubstituteTypeParams<'a> {
    source_scope: &'a SemanticsScope<'a>,
    substs: FxHashMap<hir::TypeParam, ast::Type>,
    previous: Box<dyn AstTransform<'a> + 'a>,
}

impl<'a> SubstituteTypeParams<'a> {
    pub fn for_trait_impl(
        source_scope: &'a SemanticsScope<'a>,
        // FIXME: there's implicit invariant that `trait_` and  `source_scope` match...
        trait_: hir::Trait,
        impl_def: ast::Impl,
    ) -> SubstituteTypeParams<'a> {
        let substs = get_syntactic_substs(impl_def).unwrap_or_default();
        let generic_def: hir::GenericDef = trait_.into();
        let substs_by_param: FxHashMap<_, _> = generic_def
            .params(source_scope.db)
            .into_iter()
            // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
            .skip(1)
            // The actual list of trait type parameters may be longer than the one
            // used in the `impl` block due to trailing default type parameters.
            // For that case we extend the `substs` with an empty iterator so we
            // can still hit those trailing values and check if they actually have
            // a default type. If they do, go for that type from `hir` to `ast` so
            // the resulting change can be applied correctly.
            .zip(substs.into_iter().map(Some).chain(std::iter::repeat(None)))
            .filter_map(|(k, v)| match v {
                Some(v) => Some((k, v)),
                None => {
                    let default = k.default(source_scope.db)?;
                    Some((
                        k,
                        ast::make::ty(
                            &default
                                .display_source_code(source_scope.db, source_scope.module()?.into())
                                .ok()?,
                        ),
                    ))
                }
            })
            .collect();
        return SubstituteTypeParams {
            source_scope,
            substs: substs_by_param,
            previous: Box::new(NullTransformer),
        };

        // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
        // trait ref, and then go from the types in the substs back to the syntax).
        fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> {
            let target_trait = impl_def.trait_()?;
            let path_type = match target_trait {
                ast::Type::PathType(path) => path,
                _ => return None,
            };
            let generic_arg_list = path_type.path()?.segment()?.generic_arg_list()?;

            let mut result = Vec::new();
            for generic_arg in generic_arg_list.generic_args() {
                match generic_arg {
                    ast::GenericArg::TypeArg(type_arg) => result.push(type_arg.ty()?),
                    ast::GenericArg::AssocTypeArg(_)
                    | ast::GenericArg::LifetimeArg(_)
                    | ast::GenericArg::ConstArg(_) => (),
                }
            }

            Some(result)
        }
    }
    fn get_substitution_inner(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        let type_ref = ast::Type::cast(node.clone())?;
        let path = match &type_ref {
            ast::Type::PathType(path_type) => path_type.path()?,
            _ => return None,
        };
        let resolution = self.source_scope.speculative_resolve(&path)?;
        match resolution {
            hir::PathResolution::TypeParam(tp) => Some(self.substs.get(&tp)?.syntax().clone()),
            _ => None,
        }
    }
}

impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
    fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
    }
    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
        Box::new(SubstituteTypeParams { previous: other, ..self })
    }
}

pub struct QualifyPaths<'a> {
    target_scope: &'a SemanticsScope<'a>,
    source_scope: &'a SemanticsScope<'a>,
    previous: Box<dyn AstTransform<'a> + 'a>,
}

impl<'a> QualifyPaths<'a> {
    pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self {
        Self { target_scope, source_scope, previous: Box::new(NullTransformer) }
    }

    fn get_substitution_inner(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        // FIXME handle value ns?
        let from = self.target_scope.module()?;
        let p = ast::Path::cast(node.clone())?;
        if p.segment().and_then(|s| s.param_list()).is_some() {
            // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway
            return None;
        }
        let resolution = self.source_scope.speculative_resolve(&p)?;
        match resolution {
            PathResolution::Def(def) => {
                let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?;
                let mut path = path_to_ast(found_path);

                let type_args = p
                    .segment()
                    .and_then(|s| s.generic_arg_list())
                    .map(|arg_list| apply(self, arg_list));
                if let Some(type_args) = type_args {
                    let last_segment = path.segment().unwrap();
                    path = path.with_segment(last_segment.with_generic_args(type_args))
                }

                Some(path.syntax().clone())
            }
            PathResolution::Local(_)
            | PathResolution::TypeParam(_)
            | PathResolution::SelfType(_) => None,
            PathResolution::Macro(_) => None,
            PathResolution::AssocItem(_) => None,
        }
    }
}

impl<'a> AstTransform<'a> for QualifyPaths<'a> {
    fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
    }
    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
        Box::new(QualifyPaths { previous: other, ..self })
    }
}

pub(crate) fn path_to_ast(path: hir::ModPath) -> ast::Path {
    let parse = ast::SourceFile::parse(&path.to_string());
    parse
        .tree()
        .syntax()
        .descendants()
        .find_map(ast::Path::cast)
        .unwrap_or_else(|| panic!("failed to parse path {:?}, `{}`", path, path))
}
<commit_msg>Document AstTransformation<commit_after>//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
use rustc_hash::FxHashMap;

use hir::{HirDisplay, PathResolution, SemanticsScope};
use syntax::{
    algo::SyntaxRewriter,
    ast::{self, AstNode},
};

pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
    SyntaxRewriter::from_fn(|element| match element {
        syntax::SyntaxElement::Node(n) => {
            let replacement = transformer.get_substitution(&n)?;
            Some(replacement.into())
        }
        _ => None,
    })
    .rewrite_ast(&node)
}

/// `AstTransform` helps with applying bulk transformations to syntax nodes.
///
/// This is mostly useful for IDE code generation. If you paste some existing
/// code into a new context (for example, to add method overrides to an `impl`
/// block), you generally want to appropriately qualify the names, and sometimes
/// you might want to substitute generic parameters as well:
///
/// ```
/// mod x {
///   pub struct A;
///   pub trait T<U> { fn foo(&self, _: U) -> A; }
/// }
///
/// mod y {
///   use x::T;
///
///   impl T<()> for () {
///      // If we invoke **Add Missing Members** here, we want to copy-paste `foo`.
///      // But we want a slightly-modified version of it:
///      fn foo(&self, _: ()) -> x::A {}
///   }
/// }
/// ```
///
/// So, a single `AstTransform` describes such function from `SyntaxNode` to
/// `SyntaxNode`. Note that the API here is a bit too high-order and high-brow.
/// We'd want to somehow express this concept simpler, but so far nobody got to
/// simplifying this!
pub trait AstTransform<'a> {
    fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode>;

    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a>;
    fn or<T: AstTransform<'a> + 'a>(self, other: T) -> Box<dyn AstTransform<'a> + 'a>
    where
        Self: Sized + 'a,
    {
        self.chain_before(Box::new(other))
    }
}

struct NullTransformer;

impl<'a> AstTransform<'a> for NullTransformer {
    fn get_substitution(&self, _node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        None
    }
    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
        other
    }
}

pub struct SubstituteTypeParams<'a> {
    source_scope: &'a SemanticsScope<'a>,
    substs: FxHashMap<hir::TypeParam, ast::Type>,
    previous: Box<dyn AstTransform<'a> + 'a>,
}

impl<'a> SubstituteTypeParams<'a> {
    pub fn for_trait_impl(
        source_scope: &'a SemanticsScope<'a>,
        // FIXME: there's implicit invariant that `trait_` and  `source_scope` match...
        trait_: hir::Trait,
        impl_def: ast::Impl,
    ) -> SubstituteTypeParams<'a> {
        let substs = get_syntactic_substs(impl_def).unwrap_or_default();
        let generic_def: hir::GenericDef = trait_.into();
        let substs_by_param: FxHashMap<_, _> = generic_def
            .params(source_scope.db)
            .into_iter()
            // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
            .skip(1)
            // The actual list of trait type parameters may be longer than the one
            // used in the `impl` block due to trailing default type parameters.
            // For that case we extend the `substs` with an empty iterator so we
            // can still hit those trailing values and check if they actually have
            // a default type. If they do, go for that type from `hir` to `ast` so
            // the resulting change can be applied correctly.
            .zip(substs.into_iter().map(Some).chain(std::iter::repeat(None)))
            .filter_map(|(k, v)| match v {
                Some(v) => Some((k, v)),
                None => {
                    let default = k.default(source_scope.db)?;
                    Some((
                        k,
                        ast::make::ty(
                            &default
                                .display_source_code(source_scope.db, source_scope.module()?.into())
                                .ok()?,
                        ),
                    ))
                }
            })
            .collect();
        return SubstituteTypeParams {
            source_scope,
            substs: substs_by_param,
            previous: Box::new(NullTransformer),
        };

        // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
        // trait ref, and then go from the types in the substs back to the syntax).
        fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> {
            let target_trait = impl_def.trait_()?;
            let path_type = match target_trait {
                ast::Type::PathType(path) => path,
                _ => return None,
            };
            let generic_arg_list = path_type.path()?.segment()?.generic_arg_list()?;

            let mut result = Vec::new();
            for generic_arg in generic_arg_list.generic_args() {
                match generic_arg {
                    ast::GenericArg::TypeArg(type_arg) => result.push(type_arg.ty()?),
                    ast::GenericArg::AssocTypeArg(_)
                    | ast::GenericArg::LifetimeArg(_)
                    | ast::GenericArg::ConstArg(_) => (),
                }
            }

            Some(result)
        }
    }
    fn get_substitution_inner(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        let type_ref = ast::Type::cast(node.clone())?;
        let path = match &type_ref {
            ast::Type::PathType(path_type) => path_type.path()?,
            _ => return None,
        };
        let resolution = self.source_scope.speculative_resolve(&path)?;
        match resolution {
            hir::PathResolution::TypeParam(tp) => Some(self.substs.get(&tp)?.syntax().clone()),
            _ => None,
        }
    }
}

impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
    fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
    }
    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
        Box::new(SubstituteTypeParams { previous: other, ..self })
    }
}

pub struct QualifyPaths<'a> {
    target_scope: &'a SemanticsScope<'a>,
    source_scope: &'a SemanticsScope<'a>,
    previous: Box<dyn AstTransform<'a> + 'a>,
}

impl<'a> QualifyPaths<'a> {
    pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self {
        Self { target_scope, source_scope, previous: Box::new(NullTransformer) }
    }

    fn get_substitution_inner(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        // FIXME handle value ns?
        let from = self.target_scope.module()?;
        let p = ast::Path::cast(node.clone())?;
        if p.segment().and_then(|s| s.param_list()).is_some() {
            // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway
            return None;
        }
        let resolution = self.source_scope.speculative_resolve(&p)?;
        match resolution {
            PathResolution::Def(def) => {
                let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?;
                let mut path = path_to_ast(found_path);

                let type_args = p
                    .segment()
                    .and_then(|s| s.generic_arg_list())
                    .map(|arg_list| apply(self, arg_list));
                if let Some(type_args) = type_args {
                    let last_segment = path.segment().unwrap();
                    path = path.with_segment(last_segment.with_generic_args(type_args))
                }

                Some(path.syntax().clone())
            }
            PathResolution::Local(_)
            | PathResolution::TypeParam(_)
            | PathResolution::SelfType(_) => None,
            PathResolution::Macro(_) => None,
            PathResolution::AssocItem(_) => None,
        }
    }
}

impl<'a> AstTransform<'a> for QualifyPaths<'a> {
    fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode> {
        self.get_substitution_inner(node).or_else(|| self.previous.get_substitution(node))
    }
    fn chain_before(self, other: Box<dyn AstTransform<'a> + 'a>) -> Box<dyn AstTransform<'a> + 'a> {
        Box::new(QualifyPaths { previous: other, ..self })
    }
}

pub(crate) fn path_to_ast(path: hir::ModPath) -> ast::Path {
    let parse = ast::SourceFile::parse(&path.to_string());
    parse
        .tree()
        .syntax()
        .descendants()
        .find_map(ast::Path::cast)
        .unwrap_or_else(|| panic!("failed to parse path {:?}, `{}`", path, path))
}
<|endoftext|>


<commit_before>//! Proc Macro Expander stub

use crate::{db::AstDatabase, LazyMacroId};
use base_db::{CrateId, ProcMacroId};
use tt::buffer::{Cursor, TokenBuffer};

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ProcMacroExpander {
    krate: CrateId,
    proc_macro_id: Option<ProcMacroId>,
}

macro_rules! err {
    ($fmt:literal, $($tt:tt),*) => {
        mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown(format!($fmt, $($tt),*)))
    };
    ($fmt:literal) => {
        mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown($fmt.to_string()))
    }
}

impl ProcMacroExpander {
    pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> Self {
        Self { krate, proc_macro_id: Some(proc_macro_id) }
    }

    pub fn dummy(krate: CrateId) -> Self {
        // FIXME: Should store the name for better errors
        // FIXME: I think this is the second layer of "dummy" expansion, we should reduce that
        Self { krate, proc_macro_id: None }
    }

    pub fn expand(
        self,
        db: &dyn AstDatabase,
        _id: LazyMacroId,
        tt: &tt::Subtree,
    ) -> Result<tt::Subtree, mbe::ExpandError> {
        match self.proc_macro_id {
            Some(id) => {
                let krate_graph = db.crate_graph();
                let proc_macro = krate_graph[self.krate]
                    .proc_macro
                    .get(id.0 as usize)
                    .clone()
                    .ok_or_else(|| err!("No derive macro found."))?;

                let tt = remove_derive_attrs(tt)
                    .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;

                proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
            }
            None => Err(mbe::ExpandError::UnresolvedProcMacro),
        }
    }
}

fn eat_punct(cursor: &mut Cursor, c: char) -> bool {
    if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() {
        if punct.char == c {
            *cursor = cursor.bump();
            return true;
        }
    }
    false
}

fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool {
    if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() {
        if Some(kind) == subtree.delimiter_kind() {
            *cursor = cursor.bump_subtree();
            return true;
        }
    }
    false
}

fn eat_ident(cursor: &mut Cursor, t: &str) -> bool {
    if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() {
        if t == ident.text.as_str() {
            *cursor = cursor.bump();
            return true;
        }
    }
    false
}

fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> {
    let buffer = TokenBuffer::new(&tt.token_trees);
    let mut p = buffer.begin();
    let mut result = tt::Subtree::default();

    while !p.eof() {
        let curr = p;

        if eat_punct(&mut p, '#') {
            eat_punct(&mut p, '!');
            let parent = p;
            if eat_subtree(&mut p, tt::DelimiterKind::Bracket) {
                if eat_ident(&mut p, "derive") {
                    p = parent.bump();
                    continue;
                }
            }
        }

        result.token_trees.push(curr.token_tree()?.clone());
        p = curr.bump();
    }

    Some(result)
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::assert_eq_text;

    #[test]
    fn test_remove_derive_attrs() {
        let tt = mbe::parse_to_token_tree(
            r#"
    #[allow(unused)]
    #[derive(Copy)]
    #[derive(Hello)]
    struct A {
        bar: u32
    }
"#,
        )
        .unwrap()
        .0;
        let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap());

        assert_eq_text!(
            &result,
            r#"
SUBTREE $
  PUNCH   # [alone] 0
  SUBTREE [] 1
    IDENT   allow 2
    SUBTREE () 3
      IDENT   unused 4
  IDENT   struct 15
  IDENT   A 16
  SUBTREE {} 17
    IDENT   bar 18
    PUNCH   : [alone] 19
    IDENT   u32 20
"#
            .trim()
        );
    }
}
<commit_msg>Remove resolved FIXME<commit_after>//! Proc Macro Expander stub

use crate::{db::AstDatabase, LazyMacroId};
use base_db::{CrateId, ProcMacroId};
use tt::buffer::{Cursor, TokenBuffer};

#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct ProcMacroExpander {
    krate: CrateId,
    proc_macro_id: Option<ProcMacroId>,
}

macro_rules! err {
    ($fmt:literal, $($tt:tt),*) => {
        mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown(format!($fmt, $($tt),*)))
    };
    ($fmt:literal) => {
        mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown($fmt.to_string()))
    }
}

impl ProcMacroExpander {
    pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> Self {
        Self { krate, proc_macro_id: Some(proc_macro_id) }
    }

    pub fn dummy(krate: CrateId) -> Self {
        // FIXME: Should store the name for better errors
        Self { krate, proc_macro_id: None }
    }

    pub fn expand(
        self,
        db: &dyn AstDatabase,
        _id: LazyMacroId,
        tt: &tt::Subtree,
    ) -> Result<tt::Subtree, mbe::ExpandError> {
        match self.proc_macro_id {
            Some(id) => {
                let krate_graph = db.crate_graph();
                let proc_macro = krate_graph[self.krate]
                    .proc_macro
                    .get(id.0 as usize)
                    .clone()
                    .ok_or_else(|| err!("No derive macro found."))?;

                let tt = remove_derive_attrs(tt)
                    .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;

                proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
            }
            None => Err(mbe::ExpandError::UnresolvedProcMacro),
        }
    }
}

fn eat_punct(cursor: &mut Cursor, c: char) -> bool {
    if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() {
        if punct.char == c {
            *cursor = cursor.bump();
            return true;
        }
    }
    false
}

fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool {
    if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() {
        if Some(kind) == subtree.delimiter_kind() {
            *cursor = cursor.bump_subtree();
            return true;
        }
    }
    false
}

fn eat_ident(cursor: &mut Cursor, t: &str) -> bool {
    if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() {
        if t == ident.text.as_str() {
            *cursor = cursor.bump();
            return true;
        }
    }
    false
}

fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> {
    let buffer = TokenBuffer::new(&tt.token_trees);
    let mut p = buffer.begin();
    let mut result = tt::Subtree::default();

    while !p.eof() {
        let curr = p;

        if eat_punct(&mut p, '#') {
            eat_punct(&mut p, '!');
            let parent = p;
            if eat_subtree(&mut p, tt::DelimiterKind::Bracket) {
                if eat_ident(&mut p, "derive") {
                    p = parent.bump();
                    continue;
                }
            }
        }

        result.token_trees.push(curr.token_tree()?.clone());
        p = curr.bump();
    }

    Some(result)
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::assert_eq_text;

    #[test]
    fn test_remove_derive_attrs() {
        let tt = mbe::parse_to_token_tree(
            r#"
    #[allow(unused)]
    #[derive(Copy)]
    #[derive(Hello)]
    struct A {
        bar: u32
    }
"#,
        )
        .unwrap()
        .0;
        let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap());

        assert_eq_text!(
            &result,
            r#"
SUBTREE $
  PUNCH   # [alone] 0
  SUBTREE [] 1
    IDENT   allow 2
    SUBTREE () 3
      IDENT   unused 4
  IDENT   struct 15
  IDENT   A 16
  SUBTREE {} 17
    IDENT   bar 18
    PUNCH   : [alone] 19
    IDENT   u32 20
"#
            .trim()
        );
    }
}
<|endoftext|>


<commit_before>//! Name resolution algorithm. The end result of the algorithm is `ItemMap`: a
//! map with maps each module to it's scope: the set of items, visible in the
//! module. That is, we only resolve imports here, name resolution of item
//! bodies will be done in a separate step.
//!
//! Like Rustc, we use an interative per-crate algorithm: we start with scopes
//! containing only directly defined items, and then iteratively resolve
//! imports.
//!
//! To make this work nicely in the IDE scenarios, we place `InputModuleItems`
//! in between raw syntax and name resolution. `InputModuleItems` are computed
//! using only the module's syntax, and it is all directly defined items plus
//! imports. The plain is to make `InputModuleItems` independent of local
//! modifications (that is, typing inside a function shold not change IMIs),
//! such that the results of name resolution can be preserved unless the module
//! structure itself is modified.
use std::{
    sync::Arc,
};

use rustc_hash::FxHashMap;
use ra_syntax::{
    TextRange,
    SmolStr, SyntaxKind::{self, *},
    ast::{self, AstNode}
};
use ra_db::SourceRootId;

use crate::{
    Cancelable, FileId,
    DefId, DefLoc,
    SourceItemId, SourceFileItemId, SourceFileItems,
    Path, PathKind,
    HirDatabase,
    module::{ModuleId, ModuleTree},
};

/// Item map is the result of the name resolution. Item map contains, for each
/// module, the set of visible items.
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ItemMap {
    pub per_module: FxHashMap<ModuleId, ModuleScope>,
}

#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct ModuleScope {
    items: FxHashMap<SmolStr, Resolution>,
}

impl ModuleScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a {
        self.items.iter()
    }
    pub fn get(&self, name: &SmolStr) -> Option<&Resolution> {
        self.items.get(name)
    }
}

/// A set of items and imports declared inside a module, without relation to
/// other modules.
///
/// This stands in-between raw syntax and name resolution and alow us to avoid
/// recomputing name res: if `InputModuleItems` are the same, we can avoid
/// running name resolution.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct InputModuleItems {
    items: Vec<ModuleItem>,
    imports: Vec<Import>,
}

#[derive(Debug, PartialEq, Eq)]
struct ModuleItem {
    id: SourceFileItemId,
    name: SmolStr,
    kind: SyntaxKind,
    vis: Vis,
}

#[derive(Debug, PartialEq, Eq)]
enum Vis {
    // Priv,
    Other,
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Import {
    path: Path,
    kind: ImportKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NamedImport {
    pub file_item_id: SourceFileItemId,
    pub relative_range: TextRange,
}

impl NamedImport {
    pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange {
        let source_item_id = SourceItemId {
            file_id,
            item_id: self.file_item_id,
        };
        let syntax = db.file_item(source_item_id);
        let offset = syntax.borrowed().range().start();
        self.relative_range + offset
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum ImportKind {
    Glob,
    Named(NamedImport),
}

/// Resolution is basically `DefId` atm, but it should account for stuff like
/// multiple namespaces, ambiguity and errors.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Resolution {
    /// None for unresolved
    pub def_id: Option<DefId>,
    /// ident by whitch this is imported into local scope.
    pub import: Option<NamedImport>,
}

// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
// enum Namespace {
//     Types,
//     Values,
// }

// #[derive(Debug)]
// struct PerNs<T> {
//     types: Option<T>,
//     values: Option<T>,
// }

impl InputModuleItems {
    pub(crate) fn new<'a>(
        file_items: &SourceFileItems,
        items: impl Iterator<Item = ast::ModuleItem<'a>>,
    ) -> InputModuleItems {
        let mut res = InputModuleItems::default();
        for item in items {
            res.add_item(file_items, item);
        }
        res
    }

    fn add_item(&mut self, file_items: &SourceFileItems, item: ast::ModuleItem) -> Option<()> {
        match item {
            ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::ImplItem(_) => {
                // impls don't define items
            }
            ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it),
            ast::ModuleItem::ExternCrateItem(_) => {
                // TODO
            }
            ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(file_items, it)?),
        }
        Some(())
    }

    fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) {
        let file_item_id = file_items.id_of(item.syntax());
        let start_offset = item.syntax().range().start();
        Path::expand_use_item(item, |path, range| {
            let kind = match range {
                None => ImportKind::Glob,
                Some(range) => ImportKind::Named(NamedImport {
                    file_item_id,
                    relative_range: range - start_offset,
                }),
            };
            self.imports.push(Import { kind, path })
        })
    }
}

impl ModuleItem {
    fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> {
        let name = item.name()?.text();
        let kind = item.syntax().kind();
        let vis = Vis::Other;
        let id = file_items.id_of(item.syntax());
        let res = ModuleItem {
            id,
            name,
            kind,
            vis,
        };
        Some(res)
    }
}

pub(crate) struct Resolver<'a, DB> {
    pub(crate) db: &'a DB,
    pub(crate) input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
    pub(crate) source_root: SourceRootId,
    pub(crate) module_tree: Arc<ModuleTree>,
    pub(crate) result: ItemMap,
}

impl<'a, DB> Resolver<'a, DB>
where
    DB: HirDatabase,
{
    pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> {
        for (&module_id, items) in self.input.iter() {
            self.populate_module(module_id, items)
        }

        for &module_id in self.input.keys() {
            self.db.check_canceled()?;
            self.resolve_imports(module_id);
        }
        Ok(self.result)
    }

    fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) {
        let file_id = module_id.source(&self.module_tree).file_id();

        let mut module_items = ModuleScope::default();

        for import in input.imports.iter() {
            if let Some(name) = import.path.segments.iter().last() {
                if let ImportKind::Named(import) = import.kind {
                    module_items.items.insert(
                        name.clone(),
                        Resolution {
                            def_id: None,
                            import: Some(import),
                        },
                    );
                }
            }
        }

        for item in input.items.iter() {
            if item.kind == MODULE {
                // handle submodules separatelly
                continue;
            }
            let def_loc = DefLoc::Item {
                source_item_id: SourceItemId {
                    file_id,
                    item_id: item.id,
                },
            };
            let def_id = def_loc.id(self.db);
            let resolution = Resolution {
                def_id: Some(def_id),
                import: None,
            };
            module_items.items.insert(item.name.clone(), resolution);
        }

        for (name, mod_id) in module_id.children(&self.module_tree) {
            let def_loc = DefLoc::Module {
                id: mod_id,
                source_root: self.source_root,
            };
            let def_id = def_loc.id(self.db);
            let resolution = Resolution {
                def_id: Some(def_id),
                import: None,
            };
            module_items.items.insert(name, resolution);
        }

        self.result.per_module.insert(module_id, module_items);
    }

    fn resolve_imports(&mut self, module_id: ModuleId) {
        for import in self.input[&module_id].imports.iter() {
            self.resolve_import(module_id, import);
        }
    }

    fn resolve_import(&mut self, module_id: ModuleId, import: &Import) {
        let ptr = match import.kind {
            ImportKind::Glob => return,
            ImportKind::Named(ptr) => ptr,
        };

        let mut curr = match import.path.kind {
            // TODO: handle extern crates
            PathKind::Plain => return,
            PathKind::Self_ => module_id,
            PathKind::Super => {
                match module_id.parent(&self.module_tree) {
                    Some(it) => it,
                    // TODO: error
                    None => return,
                }
            }
            PathKind::Crate => module_id.crate_root(&self.module_tree),
        };

        for (i, name) in import.path.segments.iter().enumerate() {
            let is_last = i == import.path.segments.len() - 1;

            let def_id = match self.result.per_module[&curr].items.get(name) {
                None => return,
                Some(res) => match res.def_id {
                    Some(it) => it,
                    None => return,
                },
            };

            if !is_last {
                curr = match def_id.loc(self.db) {
                    DefLoc::Module { id, .. } => id,
                    _ => return,
                }
            } else {
                self.update(module_id, |items| {
                    let res = Resolution {
                        def_id: Some(def_id),
                        import: Some(ptr),
                    };
                    items.items.insert(name.clone(), res);
                })
            }
        }
    }

    fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
        let module_items = self.result.per_module.get_mut(&module_id).unwrap();
        f(module_items)
    }
}

//TODO: move to hir
#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use salsa::Database;
    use ra_db::FilesDatabase;
    use ra_syntax::SmolStr;

    use crate::{
        self as hir,
        db::HirDatabase,
        mock::MockDatabase,
};

    fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
        let (db, pos) = MockDatabase::with_position(fixture);
        let source_root = db.file_source_root(pos.file_id);
        let module = hir::Module::guess_from_position(&db, pos).unwrap().unwrap();
        let module_id = module.module_id;
        (db.item_map(source_root).unwrap(), module_id)
    }

    #[test]
    fn test_item_map() {
        let (item_map, module_id) = item_map(
            "
            //- /lib.rs
            mod foo;

            use crate::foo::bar::Baz;
            <|>

            //- /foo/mod.rs
            pub mod bar;

            //- /foo/bar.rs
            pub struct Baz;
        ",
        );
        let name = SmolStr::from("Baz");
        let resolution = &item_map.per_module[&module_id].items[&name];
        assert!(resolution.def_id.is_some());
    }

    #[test]
    fn typing_inside_a_function_should_not_invalidate_item_map() {
        let (mut db, pos) = MockDatabase::with_position(
            "
            //- /lib.rs
            mod foo;<|>

            use crate::foo::bar::Baz;

            fn foo() -> i32 {
                1 + 1
            }
            //- /foo/mod.rs
            pub mod bar;

            //- /foo/bar.rs
            pub struct Baz;
        ",
        );
        let source_root = db.file_source_root(pos.file_id);
        {
            let events = db.log_executed(|| {
                db.item_map(source_root).unwrap();
            });
            assert!(format!("{:?}", events).contains("item_map"))
        }

        let new_text = "
            mod foo;

            use crate::foo::bar::Baz;

            fn foo() -> i32 { 92 }
        "
        .to_string();

        db.query_mut(ra_db::FileTextQuery)
            .set(pos.file_id, Arc::new(new_text));

        {
            let events = db.log_executed(|| {
                db.item_map(source_root).unwrap();
            });
            assert!(
                !format!("{:?}", events).contains("_item_map"),
                "{:#?}",
                events
            )
        }
    }
}
<commit_msg>drop comment<commit_after>//! Name resolution algorithm. The end result of the algorithm is `ItemMap`: a
//! map with maps each module to it's scope: the set of items, visible in the
//! module. That is, we only resolve imports here, name resolution of item
//! bodies will be done in a separate step.
//!
//! Like Rustc, we use an interative per-crate algorithm: we start with scopes
//! containing only directly defined items, and then iteratively resolve
//! imports.
//!
//! To make this work nicely in the IDE scenarios, we place `InputModuleItems`
//! in between raw syntax and name resolution. `InputModuleItems` are computed
//! using only the module's syntax, and it is all directly defined items plus
//! imports. The plain is to make `InputModuleItems` independent of local
//! modifications (that is, typing inside a function shold not change IMIs),
//! such that the results of name resolution can be preserved unless the module
//! structure itself is modified.
use std::{
    sync::Arc,
};

use rustc_hash::FxHashMap;
use ra_syntax::{
    TextRange,
    SmolStr, SyntaxKind::{self, *},
    ast::{self, AstNode}
};
use ra_db::SourceRootId;

use crate::{
    Cancelable, FileId,
    DefId, DefLoc,
    SourceItemId, SourceFileItemId, SourceFileItems,
    Path, PathKind,
    HirDatabase,
    module::{ModuleId, ModuleTree},
};

/// Item map is the result of the name resolution. Item map contains, for each
/// module, the set of visible items.
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ItemMap {
    pub per_module: FxHashMap<ModuleId, ModuleScope>,
}

#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct ModuleScope {
    items: FxHashMap<SmolStr, Resolution>,
}

impl ModuleScope {
    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a {
        self.items.iter()
    }
    pub fn get(&self, name: &SmolStr) -> Option<&Resolution> {
        self.items.get(name)
    }
}

/// A set of items and imports declared inside a module, without relation to
/// other modules.
///
/// This stands in-between raw syntax and name resolution and alow us to avoid
/// recomputing name res: if `InputModuleItems` are the same, we can avoid
/// running name resolution.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct InputModuleItems {
    items: Vec<ModuleItem>,
    imports: Vec<Import>,
}

#[derive(Debug, PartialEq, Eq)]
struct ModuleItem {
    id: SourceFileItemId,
    name: SmolStr,
    kind: SyntaxKind,
    vis: Vis,
}

#[derive(Debug, PartialEq, Eq)]
enum Vis {
    // Priv,
    Other,
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Import {
    path: Path,
    kind: ImportKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NamedImport {
    pub file_item_id: SourceFileItemId,
    pub relative_range: TextRange,
}

impl NamedImport {
    pub fn range(&self, db: &impl HirDatabase, file_id: FileId) -> TextRange {
        let source_item_id = SourceItemId {
            file_id,
            item_id: self.file_item_id,
        };
        let syntax = db.file_item(source_item_id);
        let offset = syntax.borrowed().range().start();
        self.relative_range + offset
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
enum ImportKind {
    Glob,
    Named(NamedImport),
}

/// Resolution is basically `DefId` atm, but it should account for stuff like
/// multiple namespaces, ambiguity and errors.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Resolution {
    /// None for unresolved
    pub def_id: Option<DefId>,
    /// ident by whitch this is imported into local scope.
    pub import: Option<NamedImport>,
}

// #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
// enum Namespace {
//     Types,
//     Values,
// }

// #[derive(Debug)]
// struct PerNs<T> {
//     types: Option<T>,
//     values: Option<T>,
// }

impl InputModuleItems {
    pub(crate) fn new<'a>(
        file_items: &SourceFileItems,
        items: impl Iterator<Item = ast::ModuleItem<'a>>,
    ) -> InputModuleItems {
        let mut res = InputModuleItems::default();
        for item in items {
            res.add_item(file_items, item);
        }
        res
    }

    fn add_item(&mut self, file_items: &SourceFileItems, item: ast::ModuleItem) -> Option<()> {
        match item {
            ast::ModuleItem::StructDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::EnumDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::FnDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::TraitDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::TypeDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::ImplItem(_) => {
                // impls don't define items
            }
            ast::ModuleItem::UseItem(it) => self.add_use_item(file_items, it),
            ast::ModuleItem::ExternCrateItem(_) => {
                // TODO
            }
            ast::ModuleItem::ConstDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::StaticDef(it) => self.items.push(ModuleItem::new(file_items, it)?),
            ast::ModuleItem::Module(it) => self.items.push(ModuleItem::new(file_items, it)?),
        }
        Some(())
    }

    fn add_use_item(&mut self, file_items: &SourceFileItems, item: ast::UseItem) {
        let file_item_id = file_items.id_of(item.syntax());
        let start_offset = item.syntax().range().start();
        Path::expand_use_item(item, |path, range| {
            let kind = match range {
                None => ImportKind::Glob,
                Some(range) => ImportKind::Named(NamedImport {
                    file_item_id,
                    relative_range: range - start_offset,
                }),
            };
            self.imports.push(Import { kind, path })
        })
    }
}

impl ModuleItem {
    fn new<'a>(file_items: &SourceFileItems, item: impl ast::NameOwner<'a>) -> Option<ModuleItem> {
        let name = item.name()?.text();
        let kind = item.syntax().kind();
        let vis = Vis::Other;
        let id = file_items.id_of(item.syntax());
        let res = ModuleItem {
            id,
            name,
            kind,
            vis,
        };
        Some(res)
    }
}

pub(crate) struct Resolver<'a, DB> {
    pub(crate) db: &'a DB,
    pub(crate) input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
    pub(crate) source_root: SourceRootId,
    pub(crate) module_tree: Arc<ModuleTree>,
    pub(crate) result: ItemMap,
}

impl<'a, DB> Resolver<'a, DB>
where
    DB: HirDatabase,
{
    pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> {
        for (&module_id, items) in self.input.iter() {
            self.populate_module(module_id, items)
        }

        for &module_id in self.input.keys() {
            self.db.check_canceled()?;
            self.resolve_imports(module_id);
        }
        Ok(self.result)
    }

    fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) {
        let file_id = module_id.source(&self.module_tree).file_id();

        let mut module_items = ModuleScope::default();

        for import in input.imports.iter() {
            if let Some(name) = import.path.segments.iter().last() {
                if let ImportKind::Named(import) = import.kind {
                    module_items.items.insert(
                        name.clone(),
                        Resolution {
                            def_id: None,
                            import: Some(import),
                        },
                    );
                }
            }
        }

        for item in input.items.iter() {
            if item.kind == MODULE {
                // handle submodules separatelly
                continue;
            }
            let def_loc = DefLoc::Item {
                source_item_id: SourceItemId {
                    file_id,
                    item_id: item.id,
                },
            };
            let def_id = def_loc.id(self.db);
            let resolution = Resolution {
                def_id: Some(def_id),
                import: None,
            };
            module_items.items.insert(item.name.clone(), resolution);
        }

        for (name, mod_id) in module_id.children(&self.module_tree) {
            let def_loc = DefLoc::Module {
                id: mod_id,
                source_root: self.source_root,
            };
            let def_id = def_loc.id(self.db);
            let resolution = Resolution {
                def_id: Some(def_id),
                import: None,
            };
            module_items.items.insert(name, resolution);
        }

        self.result.per_module.insert(module_id, module_items);
    }

    fn resolve_imports(&mut self, module_id: ModuleId) {
        for import in self.input[&module_id].imports.iter() {
            self.resolve_import(module_id, import);
        }
    }

    fn resolve_import(&mut self, module_id: ModuleId, import: &Import) {
        let ptr = match import.kind {
            ImportKind::Glob => return,
            ImportKind::Named(ptr) => ptr,
        };

        let mut curr = match import.path.kind {
            // TODO: handle extern crates
            PathKind::Plain => return,
            PathKind::Self_ => module_id,
            PathKind::Super => {
                match module_id.parent(&self.module_tree) {
                    Some(it) => it,
                    // TODO: error
                    None => return,
                }
            }
            PathKind::Crate => module_id.crate_root(&self.module_tree),
        };

        for (i, name) in import.path.segments.iter().enumerate() {
            let is_last = i == import.path.segments.len() - 1;

            let def_id = match self.result.per_module[&curr].items.get(name) {
                None => return,
                Some(res) => match res.def_id {
                    Some(it) => it,
                    None => return,
                },
            };

            if !is_last {
                curr = match def_id.loc(self.db) {
                    DefLoc::Module { id, .. } => id,
                    _ => return,
                }
            } else {
                self.update(module_id, |items| {
                    let res = Resolution {
                        def_id: Some(def_id),
                        import: Some(ptr),
                    };
                    items.items.insert(name.clone(), res);
                })
            }
        }
    }

    fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
        let module_items = self.result.per_module.get_mut(&module_id).unwrap();
        f(module_items)
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use salsa::Database;
    use ra_db::FilesDatabase;
    use ra_syntax::SmolStr;

    use crate::{
        self as hir,
        db::HirDatabase,
        mock::MockDatabase,
};

    fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
        let (db, pos) = MockDatabase::with_position(fixture);
        let source_root = db.file_source_root(pos.file_id);
        let module = hir::Module::guess_from_position(&db, pos).unwrap().unwrap();
        let module_id = module.module_id;
        (db.item_map(source_root).unwrap(), module_id)
    }

    #[test]
    fn test_item_map() {
        let (item_map, module_id) = item_map(
            "
            //- /lib.rs
            mod foo;

            use crate::foo::bar::Baz;
            <|>

            //- /foo/mod.rs
            pub mod bar;

            //- /foo/bar.rs
            pub struct Baz;
        ",
        );
        let name = SmolStr::from("Baz");
        let resolution = &item_map.per_module[&module_id].items[&name];
        assert!(resolution.def_id.is_some());
    }

    #[test]
    fn typing_inside_a_function_should_not_invalidate_item_map() {
        let (mut db, pos) = MockDatabase::with_position(
            "
            //- /lib.rs
            mod foo;<|>

            use crate::foo::bar::Baz;

            fn foo() -> i32 {
                1 + 1
            }
            //- /foo/mod.rs
            pub mod bar;

            //- /foo/bar.rs
            pub struct Baz;
        ",
        );
        let source_root = db.file_source_root(pos.file_id);
        {
            let events = db.log_executed(|| {
                db.item_map(source_root).unwrap();
            });
            assert!(format!("{:?}", events).contains("item_map"))
        }

        let new_text = "
            mod foo;

            use crate::foo::bar::Baz;

            fn foo() -> i32 { 92 }
        "
        .to_string();

        db.query_mut(ra_db::FileTextQuery)
            .set(pos.file_id, Arc::new(new_text));

        {
            let events = db.log_executed(|| {
                db.item_map(source_root).unwrap();
            });
            assert!(
                !format!("{:?}", events).contains("_item_map"),
                "{:#?}",
                events
            )
        }
    }
}
<|endoftext|>