<commit_before>use crate::{db::RootDatabase, FileId};
use hir::{HirDisplay, Ty};
use ra_syntax::ast::Pat;
use ra_syntax::{
    algo::visit::{visitor, Visitor},
    ast::{self, PatKind, TypeAscriptionOwner},
    AstNode, SmolStr, SourceFile, SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum InlayKind {
    LetBinding,
    ClosureParameter,
}

#[derive(Debug)]
pub struct InlayHint {
    pub range: TextRange,
    pub text: SmolStr,
    pub inlay_kind: InlayKind,
    pub inlay_type_string: String,
}

pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> {
    file.syntax()
        .descendants()
        .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default())
        .flatten()
        .collect()
}

fn get_inlay_hints(
    db: &RootDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Vec<InlayHint>> {
    visitor()
        .visit(|let_statement: ast::LetStmt| {
            let let_syntax = let_statement.syntax();

            if let_statement.ascribed_type().is_some() {
                return None;
            }

            let let_pat = let_statement.pat()?;
            let inlay_type_string = get_node_displayable_type(db, file_id, let_syntax, &let_pat)?
                .display(db)
                .to_string();;

            let pat_range = match let_pat.kind() {
                PatKind::BindPat(bind_pat) => bind_pat.syntax().text_range(),
                PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().text_range(),
                _ => return None,
            };

            Some(vec![InlayHint {
                range: pat_range,
                text: let_syntax.text().to_smol_string(),
                inlay_kind: InlayKind::LetBinding,
                inlay_type_string,
            }])
        })
        .visit(|closure_parameter: ast::LambdaExpr| match closure_parameter.param_list() {
            Some(param_list) => Some(
                param_list
                    .params()
                    .filter(|closure_param| closure_param.ascribed_type().is_none())
                    .filter_map(|closure_param| {
                        let closure_param_syntax = closure_param.syntax();
                        let inlay_type_string = get_node_displayable_type(
                            db,
                            file_id,
                            closure_param_syntax,
                            &closure_param.pat()?,
                        )?
                        .display(db)
                        .to_string();
                        Some(InlayHint {
                            range: closure_param_syntax.text_range(),
                            text: closure_param_syntax.text().to_smol_string(),
                            inlay_kind: InlayKind::ClosureParameter,
                            inlay_type_string,
                        })
                    })
                    .collect(),
            ),
            None => None,
        })
        .accept(&node)?
}

fn get_node_displayable_type(
    db: &RootDatabase,
    file_id: FileId,
    node_syntax: &SyntaxNode,
    node_pat: &Pat,
) -> Option<Ty> {
    let analyzer = hir::SourceAnalyzer::new(db, file_id, node_syntax, None);
    analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| {
        if let Ty::Apply(_) = resolved_type {
            Some(resolved_type)
        } else {
            None
        }
    })
}
<commit_msg>Fix the string conversions<commit_after>use crate::{db::RootDatabase, FileId};
use hir::{HirDisplay, Ty};
use ra_syntax::ast::Pat;
use ra_syntax::{
    algo::visit::{visitor, Visitor},
    ast::{self, PatKind, TypeAscriptionOwner},
    AstNode, SmolStr, SourceFile, SyntaxNode, TextRange,
};

#[derive(Debug, PartialEq, Eq)]
pub enum InlayKind {
    LetBinding,
    ClosureParameter,
}

#[derive(Debug)]
pub struct InlayHint {
    pub range: TextRange,
    pub text: SmolStr,
    pub inlay_kind: InlayKind,
    pub inlay_type_string: String,
}

pub(crate) fn inlay_hints(db: &RootDatabase, file_id: FileId, file: &SourceFile) -> Vec<InlayHint> {
    file.syntax()
        .descendants()
        .map(|node| get_inlay_hints(db, file_id, &node).unwrap_or_default())
        .flatten()
        .collect()
}

fn get_inlay_hints(
    db: &RootDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Vec<InlayHint>> {
    visitor()
        .visit(|let_statement: ast::LetStmt| {
            let let_syntax = let_statement.syntax();

            if let_statement.ascribed_type().is_some() {
                return None;
            }

            let let_pat = let_statement.pat()?;
            let inlay_type_string = get_node_displayable_type(db, file_id, let_syntax, &let_pat)?
                .display(db)
                .to_string();;

            let pat_range = match let_pat.kind() {
                PatKind::BindPat(bind_pat) => bind_pat.syntax().text_range(),
                PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().text_range(),
                _ => return None,
            };

            Some(vec![InlayHint {
                range: pat_range,
                text: let_syntax.text().to_string().into(),
                inlay_kind: InlayKind::LetBinding,
                inlay_type_string,
            }])
        })
        .visit(|closure_parameter: ast::LambdaExpr| match closure_parameter.param_list() {
            Some(param_list) => Some(
                param_list
                    .params()
                    .filter(|closure_param| closure_param.ascribed_type().is_none())
                    .filter_map(|closure_param| {
                        let closure_param_syntax = closure_param.syntax();
                        let inlay_type_string = get_node_displayable_type(
                            db,
                            file_id,
                            closure_param_syntax,
                            &closure_param.pat()?,
                        )?
                        .display(db)
                        .to_string();
                        Some(InlayHint {
                            range: closure_param_syntax.text_range(),
                            text: closure_param_syntax.text().to_string().into(),
                            inlay_kind: InlayKind::ClosureParameter,
                            inlay_type_string,
                        })
                    })
                    .collect(),
            ),
            None => None,
        })
        .accept(&node)?
}

fn get_node_displayable_type(
    db: &RootDatabase,
    file_id: FileId,
    node_syntax: &SyntaxNode,
    node_pat: &Pat,
) -> Option<Ty> {
    let analyzer = hir::SourceAnalyzer::new(db, file_id, node_syntax, None);
    analyzer.type_of_pat(db, node_pat).and_then(|resolved_type| {
        if let Ty::Apply(_) = resolved_type {
            Some(resolved_type)
        } else {
            None
        }
    })
}

{'fraction_non_alphanumeric': 0.11365931054377615, 'fraction_numerical': 0.0, 'mean_word_length': 1.6855151045701007, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2120550', 'n_tokens_mistral': 2081, 'n_tokens_neox': 2017, 'n_words': 343}