src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs RUST 2,053 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,053.
1use std::collections::BTreeSet;23use either::Either;4use hir::{FileRange, PathResolution, Semantics, TypeInfo, db::HirDatabase, sym};5use ide_db::{6    EditionedFileId, FxHashMap, RootDatabase,7    base_db::Crate,8    defs::Definition,9    imports::insert_use::remove_use_tree_if_simple,10    path_transform::PathTransform,11    search::{FileReference, FileReferenceNode, SearchScope},12    syntax_helpers::{node_ext::expr_as_name_ref, prettify_macro_expansion},13};14use itertools::{Itertools, izip};15use syntax::{16    AstNode, NodeOrToken, SyntaxKind, TextRange,17    ast::{18        self, HasArgList, HasGenericArgs, Pat, PathExpr,19        edit::{AstNodeEdit, IndentLevel},20        syntax_factory::SyntaxFactory,21    },22    syntax_editor::SyntaxEditor,23};2425use crate::{26    AssistId,27    assist_context::{AssistContext, Assists},28};2930// Assist: inline_into_callers31//32// Inline a function or method body into all of its callers where possible, creating a `let` statement per parameter33// unless the parameter can be inlined. The parameter will be inlined either if it the supplied argument is a simple local34// or if the parameter is only accessed inside the function body once.35// If all calls can be inlined the function will be removed.36//37// ```38// fn print(_: &str) {}39// fn foo$0(word: &str) {40//     if !word.is_empty() {41//         print(word);42//     }43// }44// fn bar() {45//     foo("안녕하세요");46//     foo("여러분");47// }48// ```49// ->50// ```51// fn print(_: &str) {}52//53// fn bar() {54//     {55//         let word: &str = "안녕하세요";56//         if !word.is_empty() {57//             print(word);58//         }59//     };60//     {61//         let word: &str = "여러분";62//         if !word.is_empty() {63//             print(word);64//         }65//     };66// }67// ```68pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {69    let def_file = ctx.file_id();70    let vfs_def_file = ctx.vfs_file_id();71    let name = ctx.find_node_at_offset::<ast::Name>()?;72    let ast_func = name.syntax().parent().and_then(ast::Fn::cast)?;73    let func_body = ast_func.body()?;74    let param_list = ast_func.param_list()?;7576    let function = ctx.sema.to_def(&ast_func)?;7778    let def_file_editor = SyntaxEditor::new(ast_func.syntax().tree_top()).0;79    let params = get_fn_params(ctx.sema.db, function, &param_list, def_file_editor.make())?;8081    let mut file_editors = FxHashMap::default();82    file_editors.insert(vfs_def_file, def_file_editor);8384    let usages = Definition::Function(function).usages(&ctx.sema);85    if !usages.at_least_one() {86        return None;87    }8889    let is_recursive_fn = usages90        .clone()91        .in_scope(&SearchScope::file_range(FileRange {92            file_id: def_file,93            range: func_body.syntax().text_range(),94        }))95        .at_least_one();96    if is_recursive_fn {97        cov_mark::hit!(inline_into_callers_recursive);98        return None;99    }100101    acc.add(102        AssistId::refactor_inline("inline_into_callers"),103        "Inline into all callers",104        name.syntax().text_range(),105        |builder| {106            let mut usages = usages.all();107            let current_file_usage = usages.references.remove(&def_file);108109            let mut remove_def = true;110            let mut inline_refs_for_file = |file_id: EditionedFileId, refs: Vec<FileReference>| {111                let file_id = file_id.file_id(ctx.db());112                builder.edit_file(file_id);113                let call_krate = ctx.sema.file_to_module_def(file_id).map(|it| it.krate(ctx.db()));114                let count = refs.len();115                let (name_refs, use_trees) = split_refs_and_uses(refs, Some);116                let call_infos: Vec<_> = name_refs117                    .into_iter()118                    .filter_map(|it| CallInfo::from_name_ref(it, call_krate?.into()))119                    // FIXME: do not handle callsites in macros' parameters, because120                    // directly inlining into macros may cause errors.121                    .filter(|call_info| !ctx.sema.hir_file_for(call_info.node.syntax()).is_macro())122                    .collect();123124                // Skip calls nested inside other calls being inlined to avoid overlapping125                // edits. Nested calls are implicitly replaced when the outer call is inlined.126                let all_ranges: Vec<TextRange> =127                    call_infos.iter().map(|ci| ci.node.syntax().text_range()).collect();128                let (call_infos, nested_infos): (Vec<_>, Vec<_>) =129                    call_infos.into_iter().partition(|ci| {130                        let r = ci.node.syntax().text_range();131                        !all_ranges.iter().any(|&other| other != r && other.contains_range(r))132                    });133                let nested_count = nested_infos.len();134135                let anchor = call_infos136                    .first()137                    .map(|ci| ci.node.syntax().clone())138                    .or_else(|| use_trees.first().map(|ut| ut.syntax().clone()));139                if let Some(anchor) = anchor {140                    let editor =141                        file_editors.entry(file_id).or_insert_with(|| builder.make_editor(&anchor));142                    let replaced = call_infos143                        .into_iter()144                        .map(|call_info| {145                            let indent = call_info.node.indent_level();146                            let replacement = inline(147                                &ctx.sema, def_file, function, &func_body, &params, &call_info,148                                editor, indent,149                            );150                            editor.replace(call_info.node.syntax(), replacement.syntax());151                        })152                        .count();153                    if replaced + nested_count + use_trees.len() == count {154                        // we replaced all usages in this file, so we can remove the imports155                        for use_tree in &use_trees {156                            remove_use_tree_if_simple(use_tree, editor);157                        }158                    } else {159                        remove_def = false;160                    }161                } else if use_trees.len() != count {162                    remove_def = false;163                }164            };165            for (file_id, refs) in usages.into_iter() {166                inline_refs_for_file(file_id, refs);167            }168            match current_file_usage {169                Some(refs) => inline_refs_for_file(def_file, refs),170                None => builder.edit_file(vfs_def_file),171            }172            if remove_def {173                file_editors174                    .entry(vfs_def_file)175                    .or_insert_with(|| builder.make_editor(ast_func.syntax()))176                    .delete(ast_func.syntax());177            }178            for (file_id, editor) in file_editors {179                builder.add_file_edits(file_id, editor);180            }181        },182    )183}184185pub(super) fn split_refs_and_uses<T: ast::AstNode>(186    iter: impl IntoIterator<Item = FileReference>,187    mut map_ref: impl FnMut(ast::NameRef) -> Option<T>,188) -> (Vec<T>, Vec<ast::UseTree>) {189    iter.into_iter()190        .filter_map(|file_ref| match file_ref.name {191            FileReferenceNode::NameRef(name_ref) => Some(name_ref),192            _ => None,193        })194        .filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {195            Some(use_tree) => Some(Either::Right(use_tree)),196            None => map_ref(name_ref).map(Either::Left),197        })198        .partition_map(|either| either)199}200201// Assist: inline_call202//203// Inlines a function or method body creating a `let` statement per parameter unless the parameter204// can be inlined. The parameter will be inlined either if it the supplied argument is a simple local205// or if the parameter is only accessed inside the function body once.206//207// ```208// # //- minicore: option209// fn foo(name: Option<&str>) {210//     let name = name.unwrap$0();211// }212// ```213// ->214// ```215// fn foo(name: Option<&str>) {216//     let name = match name {217//             Some(val) => val,218//             None => panic!("called `Option::unwrap()` on a `None` value"),219//         };220// }221// ```222pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext<'_, '_>) -> Option<()> {223    let name_ref: ast::NameRef = ctx.find_node_at_offset_with_descend()?;224    let call_info = CallInfo::from_name_ref(225        name_ref.clone(),226        ctx.sema.file_to_module_def(ctx.vfs_file_id())?.krate(ctx.db()).into(),227    )?;228    let (function, label) = match &call_info.node {229        ast::CallableExpr::Call(call) => {230            let path = match call.expr()? {231                ast::Expr::PathExpr(path) => path.path(),232                _ => None,233            }?;234            let function = match ctx.sema.resolve_path(&path)? {235                PathResolution::Def(hir::ModuleDef::Function(f)) => f,236                _ => return None,237            };238            (function, format!("Inline `{path}`"))239        }240        ast::CallableExpr::MethodCall(call) => {241            (ctx.sema.resolve_method_call(call)?, format!("Inline `{name_ref}`"))242        }243    };244245    let fn_source = ctx.sema.source(function)?;246    let fn_body = fn_source.value.body()?;247    let param_list = fn_source.value.param_list()?;248249    let FileRange { file_id, range } = fn_source.syntax().original_file_range_rooted(ctx.sema.db);250    if file_id == ctx.file_id() && range.contains(ctx.offset()) {251        cov_mark::hit!(inline_call_recursive);252        return None;253    }254    let original = ctx.sema.original_range_opt(call_info.node.syntax())?.range;255    let edit_range = crate::utils::cover_edit_range(ctx.source_file().syntax(), original);256    let editor = SyntaxEditor::new(ctx.source_file().syntax().clone()).0;257    let text_range = edit_range.start().text_range().cover(edit_range.end().text_range());258    let params = get_fn_params(ctx.sema.db, function, &param_list, editor.make())?;259260    if call_info.arguments.len() != params.len() {261        // Can't inline the function because they've passed the wrong number of262        // arguments to this function263        cov_mark::hit!(inline_call_incorrect_number_of_arguments);264        return None;265    }266267    acc.add(AssistId::refactor_inline("inline_call"), label, text_range, |builder| {268        let replacement = inline(269            &ctx.sema,270            file_id,271            function,272            &fn_body,273            &params,274            &call_info,275            &editor,276            IndentLevel::from_element(edit_range.start()),277        );278        editor.replace_all(edit_range, vec![replacement.syntax().clone().into()]);279        builder.add_file_edits(ctx.vfs_file_id(), editor);280    })281}282283struct CallInfo {284    node: ast::CallableExpr,285    arguments: Vec<ast::Expr>,286    generic_arg_list: Option<ast::GenericArgList>,287    krate: Crate,288}289290impl CallInfo {291    fn from_name_ref(name_ref: ast::NameRef, krate: Crate) -> Option<CallInfo> {292        let parent = name_ref.syntax().parent()?;293        if let Some(call) = ast::MethodCallExpr::cast(parent.clone()) {294            let receiver = call.receiver()?;295            let mut arguments = vec![receiver];296            arguments.extend(call.arg_list()?.args());297            Some(CallInfo {298                generic_arg_list: call.generic_arg_list(),299                node: ast::CallableExpr::MethodCall(call),300                arguments,301                krate,302            })303        } else if let Some(segment) = ast::PathSegment::cast(parent) {304            let path = segment.syntax().parent().and_then(ast::Path::cast)?;305            let path = path.syntax().parent().and_then(ast::PathExpr::cast)?;306            let call = path.syntax().parent().and_then(ast::CallExpr::cast)?;307308            Some(CallInfo {309                arguments: call.arg_list()?.args().collect(),310                node: ast::CallableExpr::Call(call),311                generic_arg_list: segment.generic_arg_list(),312                krate,313            })314        } else {315            None316        }317    }318}319320fn get_fn_params<'db>(321    db: &'db dyn HirDatabase,322    function: hir::Function,323    param_list: &ast::ParamList,324    make: &SyntaxFactory,325) -> Option<Vec<(ast::Pat, Option<ast::Type>, hir::Param<'db>)>> {326    let mut assoc_fn_params = function.assoc_fn_params(db).into_iter();327328    let mut params = Vec::new();329    if let Some(self_param) = param_list.self_param() {330        // Keep `ref` and `mut` and transform them into `&` and `mut` later331        params.push((332            make.ident_pat(333                self_param.amp_token().is_some(),334                self_param.mut_token().is_some(),335                make.name("this"),336            )337            .into(),338            None,339            assoc_fn_params.next()?,340        ));341    }342    for param in param_list.params() {343        params.push((param.pat()?, param.ty(), assoc_fn_params.next()?));344    }345346    Some(params)347}348349fn inline<'db>(350    sema: &Semantics<'db, RootDatabase>,351    function_def_file_id: EditionedFileId,352    function: hir::Function,353    fn_body: &ast::BlockExpr,354    params: &[(ast::Pat, Option<ast::Type>, hir::Param<'db>)],355    CallInfo { node, arguments, generic_arg_list, krate }: &CallInfo,356    file_editor: &SyntaxEditor,357    original_indentation: IndentLevel,358) -> ast::Expr {359    let make = file_editor.make();360    let file_id = sema.hir_file_for(fn_body.syntax());361362    // Capture before `with_ast_node` re-roots and loses the source-relative position.363    let mut original_body_indent = IndentLevel::from_node(fn_body.syntax());364    let body_offset = fn_body.syntax().text_range().start();365    let (editor, body) = SyntaxEditor::with_ast_node(fn_body);366367    let usages_for_locals = |local| {368        Definition::Local(local)369            .usages(sema)370            .all()371            .references372            .remove(&function_def_file_id)373            .unwrap_or_default()374            .into_iter()375    };376    let param_use_nodes: Vec<Vec<_>> = params377        .iter()378        .map(|(pat, _, param)| {379            if !matches!(pat, ast::Pat::IdentPat(pat) if pat.is_simple_ident()) {380                return Vec::new();381            }382            // FIXME: we need to fetch all locals declared in the parameter here383            // not only the local if it is a simple binding384            match param.as_local(sema.db) {385                Some(l) => usages_for_locals(l)386                    .map(|FileReference { name, .. }| match name {387                        FileReferenceNode::NameRef(it) => body388                            .syntax()389                            .covering_element(it.syntax().text_range() - body_offset)390                            .ancestors()391                            .nth(3)392                            .and_then(ast::PathExpr::cast),393                        _ => None,394                    })395                    .collect::<Option<Vec<_>>>()396                    .unwrap_or_default(),397                None => Vec::new(),398            }399        })400        .collect();401402    let has_self_param = function.self_param(sema.db).is_some();403404    // Collect all self token usages upfront (needed when a let binding is emitted).405    // When self can be directly inlined, the parameter loop handles those PathExprs;406    // when a let stmt is needed, we rename all self tokens to `this` here.407    let self_token_usages: Vec<_> = if has_self_param {408        params[0]409            .2410            .as_local(sema.db)411            .map(|self_local| {412                usages_for_locals(self_local)413                    .filter_map(|FileReference { name, .. }| match name {414                        FileReferenceNode::NameRef(it) => Some(415                            body.syntax().covering_element(it.syntax().text_range() - body_offset),416                        ),417                        _ => None,418                    })419                    .collect()420            })421            .unwrap_or_default()422    } else {423        Vec::new()424    };425426    // Replace `Self` type keywords with the actual impl type427    if let Some(imp) =428        sema.ancestors_with_macros(fn_body.syntax().clone()).find_map(ast::Impl::cast)429        && !node.syntax().ancestors().any(|anc| &anc == imp.syntax())430        && let Some(t) = imp.self_ty()431    {432        let self_tokens: Vec<_> = body433            .syntax()434            .descendants_with_tokens()435            .filter_map(NodeOrToken::into_token)436            .filter(|tok| tok.kind() == SyntaxKind::SELF_TYPE_KW)437            .collect();438        for self_tok in self_tokens {439            let replace_with = if !is_in_type_path(&self_tok)440                && let Some(generic_arg_list) = t.generic_arg_list()441            {442                // Strip the outer generic arg list and reparse, since turbofish-less443                // generics aren't valid in expression position. The outermost444                // `GenericArgList` text is unique within `t`'s text (any inner generics445                // are nested inside it), so `replacen(.., 1)` is safe.446                let stripped = t.syntax().text().to_string().replacen(447                    &generic_arg_list.syntax().text().to_string(),448                    "",449                    1,450                );451                editor.make().ty(&stripped).syntax().clone()452            } else {453                t.syntax().clone()454            };455            editor.replace(self_tok, replace_with);456        }457    }458459    let mut func_let_vars: BTreeSet<String> = BTreeSet::new();460461    // grab all of the local variable declarations in the function462    for stmt in fn_body.statements() {463        if let Some(let_stmt) = ast::LetStmt::cast(stmt.syntax().to_owned()) {464            for has_token in let_stmt.syntax().children_with_tokens() {465                if let Some(node) = has_token.as_node()466                    && let Some(ident_pat) = ast::IdentPat::cast(node.to_owned())467                {468                    func_let_vars.insert(ident_pat.syntax().text().to_string());469                }470            }471        }472    }473474    let mut let_stmts: Vec<ast::Stmt> = Vec::new();475476    let this_token = editor477        .make()478        .name_ref("this")479        .syntax()480        .first_token()481        .expect("NameRef should have had a token.");482    let rewrite_self_to_this = |editor: &SyntaxEditor| {483        for usage in &self_token_usages {484            editor.replace(usage.clone(), this_token.clone());485        }486    };487488    // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.489    for ((pat, param_ty, param), usages, expr) in izip!(params, param_use_nodes, arguments) {490        // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors491        let usages: &[ast::PathExpr] = &usages;492        let expr: &ast::Expr = expr;493494        let mut insert_let_stmt = || {495            let param_ty = param_ty.clone().map(|param_ty| {496                let file_id = sema.hir_file_for(param_ty.syntax());497                if let Some(macro_file) = file_id.macro_file() {498                    let span_map = macro_file.expansion_span_map(sema.db);499                    let param_ty_prettified = prettify_macro_expansion(500                        sema.db,501                        param_ty.syntax().clone(),502                        span_map,503                        *krate,504                    );505                    ast::Type::cast(param_ty_prettified).unwrap_or(param_ty)506                } else {507                    param_ty508                }509            });510511            let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty);512513            let is_self = param.name(sema.db).is_some_and(|name| name == sym::self_);514515            if is_self {516                let mut this_pat = make.ident_pat(false, false, make.name("this"));517                let mut expr = expr.clone();518                if let Pat::IdentPat(pat) = pat {519                    match (pat.ref_token(), pat.mut_token()) {520                        // self => let this = obj521                        (None, None) => {}522                        // mut self => let mut this = obj523                        (None, Some(_)) => {524                            this_pat = make.ident_pat(false, true, make.name("this"));525                        }526                        // &self => let this = &obj527                        (Some(_), None) => {528                            expr = make.expr_ref(expr, false);529                        }530                        // let foo = &mut X; &mut self => let this = &mut obj531                        // let mut foo = X;  &mut self => let this = &mut *obj (reborrow)532                        (Some(_), Some(_)) => {533                            let should_reborrow = sema534                                .type_of_expr(&expr)535                                .map(|ty| ty.original.is_mutable_reference());536                            expr = if let Some(true) = should_reborrow {537                                make.expr_reborrow(expr)538                            } else {539                                make.expr_ref(expr, true)540                            };541                        }542                    }543                };544                let_stmts.push(make.let_stmt(this_pat.into(), ty, Some(expr)).into())545            } else {546                let_stmts.push(make.let_stmt(pat.clone(), ty, Some(expr.clone())).into());547            }548        };549550        let is_self_param =551            has_self_param && param.name(sema.db).is_some_and(|name| name == sym::self_);552553        // check if there is a local var in the function that conflicts with parameter554        // if it does then emit a let statement and continue555        if func_let_vars.contains(&expr.syntax().text().to_string()) {556            if is_self_param {557                rewrite_self_to_this(&editor);558            }559            insert_let_stmt();560            continue;561        }562563        let inline_direct = |editor: &SyntaxEditor, usage: &PathExpr, replacement: &ast::Expr| {564            if let Some(field) = path_expr_as_record_field(usage) {565                cov_mark::hit!(inline_call_inline_direct_field);566                field.replace_expr(editor, replacement.clone());567            } else {568                editor.replace(usage.syntax(), replacement.syntax());569            }570        };571572        match usages {573            // inline single use closure arguments574            [usage]575                if matches!(expr, ast::Expr::ClosureExpr(_))576                    && usage.syntax().parent().and_then(ast::Expr::cast).is_some() =>577            {578                cov_mark::hit!(inline_call_inline_closure);579                let expr = editor.make().expr_paren(expr.clone()).into();580                inline_direct(&editor, usage, &expr);581            }582            // inline single use literals583            [usage] if matches!(expr, ast::Expr::Literal(_)) => {584                cov_mark::hit!(inline_call_inline_literal);585                inline_direct(&editor, usage, expr);586            }587            // inline direct local arguments588            [_, ..] if expr_as_name_ref(expr).is_some() => {589                cov_mark::hit!(inline_call_inline_locals);590                usages.iter().for_each(|usage| inline_direct(&editor, usage, expr));591            }592            // can't inline, emit a let statement593            _ => {594                if is_self_param {595                    // Rename all `self` tokens to `this` so the let binding matches.596                    rewrite_self_to_this(&editor);597                }598                insert_let_stmt();599            }600        }601    }602603    // Apply all edits to get the transformed body604    let edit = editor.finish();605    let mut body = ast::BlockExpr::cast(edit.new_root().clone())606        .expect("editor root should still be a BlockExpr");607608    // Apply generic substitution (needs immutable tree)609    if let Some(generic_arg_list) = generic_arg_list.clone()610        && let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))611        && let Some(new_body) = ast::BlockExpr::cast(612            PathTransform::function_call(target, source, function, generic_arg_list)613                .apply(body.syntax()),614        )615    {616        body = new_body;617    }618    if let Some(macro_file) = file_id.macro_file() {619        cov_mark::hit!(inline_call_defined_in_macro);620        let span_map = macro_file.expansion_span_map(sema.db);621        let body_prettified =622            prettify_macro_expansion(sema.db, body.syntax().clone(), span_map, *krate);623        body = ast::BlockExpr::cast(body_prettified).unwrap();624    }625626    let is_async_fn = function.is_async(sema.db);627    if is_async_fn {628        cov_mark::hit!(inline_call_async_fn);629        body = make.async_move_block_expr(body.statements(), body.tail_expr());630631        // Arguments should be evaluated outside the async block, and then moved into it.632        if !let_stmts.is_empty() {633            cov_mark::hit!(inline_call_async_fn_with_let_stmts);634            body = body.indent(IndentLevel(1));635            body = make.block_expr(let_stmts, Some(body.into()));636        }637    } else if !let_stmts.is_empty() {638        // Prepend let statements to the body's existing statements639        let stmts: Vec<ast::Stmt> = let_stmts.into_iter().chain(body.statements()).collect();640        body = make.block_expr(stmts, body.tail_expr());641        original_body_indent = IndentLevel(0);642    }643644    body = body.dedent(original_body_indent).indent(original_indentation);645646    let no_stmts = body.statements().next().is_none();647    match body.tail_expr() {648        Some(expr) if matches!(expr, ast::Expr::ClosureExpr(_)) && no_stmts => {649            make.expr_paren(expr).into()650        }651        Some(expr) if !is_async_fn && no_stmts => expr,652        _ => match node653            .syntax()654            .parent()655            .and_then(ast::BinExpr::cast)656            .and_then(|bin_expr| bin_expr.lhs())657        {658            Some(lhs) if lhs.syntax() == node.syntax() => {659                make.expr_paren(ast::Expr::BlockExpr(body)).into()660            }661            _ => ast::Expr::BlockExpr(body),662        },663    }664}665666fn is_in_type_path(self_tok: &syntax::SyntaxToken) -> bool {667    self_tok668        .parent_ancestors()669        .skip_while(|it| !ast::Path::can_cast(it.kind()))670        .map_while(ast::Path::cast)671        .last()672        .and_then(|it| it.syntax().parent())673        .and_then(ast::PathType::cast)674        .is_some()675}676677fn path_expr_as_record_field(usage: &PathExpr) -> Option<ast::RecordExprField> {678    let path = usage.path()?;679    let name_ref = path.as_single_name_ref()?;680    ast::RecordExprField::for_name_ref(&name_ref)681}682683#[cfg(test)]684mod tests {685    use crate::tests::{check_assist, check_assist_not_applicable};686687    use super::*;688689    #[test]690    fn no_args_or_return_value_gets_inlined_without_block() {691        check_assist(692            inline_call,693            r#"694fn foo() { println!("Hello, World!"); }695fn main() {696    fo$0o();697}698"#,699            r#"700fn foo() { println!("Hello, World!"); }701fn main() {702    { println!("Hello, World!"); };703}704"#,705        );706    }707708    #[test]709    fn not_applicable_when_incorrect_number_of_parameters_are_provided() {710        cov_mark::check!(inline_call_incorrect_number_of_arguments);711        check_assist_not_applicable(712            inline_call,713            r#"714fn add(a: u32, b: u32) -> u32 { a + b }715fn main() { let x = add$0(42); }716"#,717        );718    }719720    #[test]721    fn args_with_side_effects() {722        check_assist(723            inline_call,724            r#"725fn foo(name: String) {726    println!("Hello, {}!", name);727}728fn main() {729    foo$0(String::from("Michael"));730}731"#,732            r#"733fn foo(name: String) {734    println!("Hello, {}!", name);735}736fn main() {737    {738        let name = String::from("Michael");739        println!("Hello, {}!", name);740    };741}742"#,743        );744    }745746    #[test]747    fn function_with_multiple_statements() {748        check_assist(749            inline_call,750            r#"751fn foo(a: u32, b: u32) -> u32 {752    let x = a + b;753    let y = x - b;754    x * y755}756757fn main() {758    let x = foo$0(1, 2);759}760"#,761            r#"762fn foo(a: u32, b: u32) -> u32 {763    let x = a + b;764    let y = x - b;765    x * y766}767768fn main() {769    let x = {770        let b = 2;771        let x = 1 + b;772        let y = x - b;773        x * y774    };775}776"#,777        );778    }779780    #[test]781    fn call_inside_macro() {782        check_assist(783            inline_call,784            r#"785macro_rules! identity { ($($t:tt)*) => { $($t)* }; }786fn foo(a: u32, b: u32) -> u32 {787    let x = a + b;788    let y = x - b;789    x * y790}791792fn main() {793    identity! {794        let x = foo$0(1, 2);795    }796}797"#,798            r#"799macro_rules! identity { ($($t:tt)*) => { $($t)* }; }800fn foo(a: u32, b: u32) -> u32 {801    let x = a + b;802    let y = x - b;803    x * y804}805806fn main() {807    identity! {808        let x = {809            let b = 2;810            let x = 1 + b;811            let y = x - b;812            x * y813        };814    }815}816"#,817        );818    }819820    #[test]821    fn function_with_self_param() {822        check_assist(823            inline_call,824            r#"825struct Foo(u32);826827impl Foo {828    fn add(self, a: u32) -> Self {829        Foo(self.0 + a)830    }831}832833fn main() {834    let x = Foo::add$0(Foo(3), 2);835}836"#,837            r#"838struct Foo(u32);839840impl Foo {841    fn add(self, a: u32) -> Self {842        Foo(self.0 + a)843    }844}845846fn main() {847    let x = {848        let this = Foo(3);849        Foo(this.0 + 2)850    };851}852"#,853        );854    }855856    #[test]857    fn method_by_val() {858        check_assist(859            inline_call,860            r#"861struct Foo(u32);862863impl Foo {864    fn add(self, a: u32) -> Self {865        Foo(self.0 + a)866    }867}868869fn main() {870    let x = Foo(3).add$0(2);871}872"#,873            r#"874struct Foo(u32);875876impl Foo {877    fn add(self, a: u32) -> Self {878        Foo(self.0 + a)879    }880}881882fn main() {883    let x = {884        let this = Foo(3);885        Foo(this.0 + 2)886    };887}888"#,889        );890    }891892    #[test]893    fn method_by_ref() {894        check_assist(895            inline_call,896            r#"897struct Foo(u32);898899impl Foo {900    fn add(&self, a: u32) -> Self {901        Foo(self.0 + a)902    }903}904905fn main() {906    let x = Foo(3).add$0(2);907}908"#,909            r#"910struct Foo(u32);911912impl Foo {913    fn add(&self, a: u32) -> Self {914        Foo(self.0 + a)915    }916}917918fn main() {919    let x = {920        let this = &Foo(3);921        Foo(this.0 + 2)922    };923}924"#,925        );926    }927928    #[test]929    fn generic_method_by_ref() {930        check_assist(931            inline_call,932            r#"933struct Foo(u32);934935impl Foo {936    fn add<T>(&self, a: u32) -> Self {937        Foo(self.0 + a)938    }939}940941fn main() {942    let x = Foo(3).add$0::<usize>(2);943}944"#,945            r#"946struct Foo(u32);947948impl Foo {949    fn add<T>(&self, a: u32) -> Self {950        Foo(self.0 + a)951    }952}953954fn main() {955    let x = {956        let this = &Foo(3);957        Foo(this.0 + 2)958    };959}960"#,961        );962    }963964    #[test]965    fn method_by_ref_mut() {966        check_assist(967            inline_call,968            r#"969struct Foo(u32);970971impl Foo {972    fn clear(&mut self) {973        self.0 = 0;974    }975}976977fn main() {978    let mut foo = Foo(3);979    foo.clear$0();980}981"#,982            r#"983struct Foo(u32);984985impl Foo {986    fn clear(&mut self) {987        self.0 = 0;988    }989}990991fn main() {992    let mut foo = Foo(3);993    {994        let this = &mut foo;995        this.0 = 0;996    };997}998"#,999        );1000    }10011002    #[test]1003    fn function_multi_use_expr_in_param() {1004        check_assist(1005            inline_call,1006            r#"1007fn square(x: u32) -> u32 {1008    x * x1009}1010fn main() {1011    let x = 51;1012    let y = square$0(10 + x);1013}1014"#,1015            r#"1016fn square(x: u32) -> u32 {1017    x * x1018}1019fn main() {1020    let x = 51;1021    let y = {1022        let x = 10 + x;1023        x * x1024    };1025}1026"#,1027        );1028    }10291030    #[test]1031    fn function_use_local_in_param() {1032        cov_mark::check!(inline_call_inline_locals);1033        check_assist(1034            inline_call,1035            r#"1036fn square(x: u32) -> u32 {1037    x * x1038}1039fn main() {1040    let local = 51;1041    let y = square$0(local);1042}1043"#,1044            r#"1045fn square(x: u32) -> u32 {1046    x * x1047}1048fn main() {1049    let local = 51;1050    let y = local * local;1051}1052"#,1053        );1054    }10551056    #[test]1057    fn method_in_impl() {1058        check_assist(1059            inline_call,1060            r#"1061struct Foo;1062impl Foo {1063    fn foo(&self) {1064        self;1065        self;1066    }1067    fn bar(&self) {1068        self.foo$0();1069    }1070}1071"#,1072            r#"1073struct Foo;1074impl Foo {1075    fn foo(&self) {1076        self;1077        self;1078    }1079    fn bar(&self) {1080        {1081            let this = &self;1082            this;1083            this;1084        };1085    }1086}1087"#,1088        );1089    }10901091    #[test]1092    fn wraps_closure_in_paren() {1093        cov_mark::check!(inline_call_inline_closure);1094        check_assist(1095            inline_call,1096            r#"1097fn foo(x: fn()) {1098    x();1099}11001101fn main() {1102    foo$0(|| {})1103}1104"#,1105            r#"1106fn foo(x: fn()) {1107    x();1108}11091110fn main() {1111    {1112        (|| {})();1113    }1114}1115"#,1116        );1117        check_assist(1118            inline_call,1119            r#"1120fn foo(x: fn()) {1121    x();1122}11231124fn main() {1125    foo$0(main)1126}1127"#,1128            r#"1129fn foo(x: fn()) {1130    x();1131}11321133fn main() {1134    {1135        main();1136    }1137}1138"#,1139        );1140    }11411142    #[test]1143    fn inline_single_literal_expr() {1144        cov_mark::check!(inline_call_inline_literal);1145        check_assist(1146            inline_call,1147            r#"1148fn foo(x: u32) -> u32{1149    x1150}11511152fn main() {1153    foo$0(222);1154}1155"#,1156            r#"1157fn foo(x: u32) -> u32{1158    x1159}11601161fn main() {1162    222;1163}1164"#,1165        );1166    }11671168    #[test]1169    fn inline_emits_type_for_coercion() {1170        check_assist(1171            inline_call,1172            r#"1173//- minicore: sized1174fn foo(x: *const u32) -> u32 {1175    x as u321176}11771178fn main() {1179    foo$0(&222);1180}1181"#,1182            r#"1183fn foo(x: *const u32) -> u32 {1184    x as u321185}11861187fn main() {1188    {1189        let x: *const u32 = &222;1190        x as u321191    };1192}1193"#,1194        );1195    }11961197    #[test]1198    fn inline_substitutes_generics() {1199        check_assist(1200            inline_call,1201            r#"1202fn foo<T, const N: usize>() {1203    bar::<T, N>()1204}12051206fn bar<U, const M: usize>() {}12071208fn main() {1209    foo$0::<usize, {0}>();1210}1211"#,1212            r#"1213fn foo<T, const N: usize>() {1214    bar::<T, N>()1215}12161217fn bar<U, const M: usize>() {}12181219fn main() {1220    bar::<usize, {0}>();1221}1222"#,1223        );1224    }12251226    #[test]1227    fn inline_callers() {1228        check_assist(1229            inline_into_callers,1230            r#"1231fn do_the_math$0(b: u32) -> u32 {1232    let foo = 10;1233    foo * b + foo1234}1235fn foo() {1236    do_the_math(0);1237    let bar = 10;1238    do_the_math(bar);1239}1240"#,1241            r#"12421243fn foo() {1244    {1245        let foo = 10;1246        foo * 0 + foo1247    };1248    let bar = 10;1249    {1250        let foo = 10;1251        foo * bar + foo1252    };1253}1254"#,1255        );1256    }12571258    #[test]1259    fn inline_callers_across_files() {1260        check_assist(1261            inline_into_callers,1262            r#"1263//- /lib.rs1264mod foo;1265fn do_the_math$0(b: u32) -> u32 {1266    let foo = 10;1267    foo * b + foo1268}1269//- /foo.rs1270use super::do_the_math;1271fn foo() {1272    do_the_math(0);1273    let bar = 10;1274    do_the_math(bar);1275}1276"#,1277            r#"1278//- /lib.rs1279mod foo;12801281//- /foo.rs1282fn foo() {1283    {1284        let foo = 10;1285        foo * 0 + foo1286    };1287    let bar = 10;1288    {1289        let foo = 10;1290        foo * bar + foo1291    };1292}1293"#,1294        );1295    }12961297    #[test]1298    fn inline_callers_across_files_with_def_file() {1299        check_assist(1300            inline_into_callers,1301            r#"1302//- /lib.rs1303mod foo;1304fn do_the_math$0(b: u32) -> u32 {1305    let foo = 10;1306    foo * b + foo1307}1308fn bar(a: u32, b: u32) -> u32 {1309    do_the_math(0);1310}1311//- /foo.rs1312use super::do_the_math;1313fn foo() {1314    do_the_math(0);1315}1316"#,1317            r#"1318//- /lib.rs1319mod foo;13201321fn bar(a: u32, b: u32) -> u32 {1322    {1323        let foo = 10;1324        foo * 0 + foo1325    };1326}1327//- /foo.rs1328fn foo() {1329    {1330        let foo = 10;1331        foo * 0 + foo1332    };1333}1334"#,1335        );1336    }13371338    #[test]1339    fn inline_callers_recursive() {1340        cov_mark::check!(inline_into_callers_recursive);1341        check_assist_not_applicable(1342            inline_into_callers,1343            r#"1344fn foo$0() {1345    foo();1346}1347"#,1348        );1349    }13501351    #[test]1352    fn inline_call_recursive() {1353        cov_mark::check!(inline_call_recursive);1354        check_assist_not_applicable(1355            inline_call,1356            r#"1357fn foo() {1358    foo$0();1359}1360"#,1361        );1362    }13631364    #[test]1365    fn inline_call_field_shorthand() {1366        cov_mark::check!(inline_call_inline_direct_field);1367        check_assist(1368            inline_call,1369            r#"1370struct Foo {1371    field: u32,1372    field1: u32,1373    field2: u32,1374    field3: u32,1375}1376fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {1377    Foo {1378        field,1379        field1,1380        field2: val2,1381        field3: val3,1382    }1383}1384fn main() {1385    let bar = 0;1386    let baz = 0;1387    foo$0(bar, 0, baz, 0);1388}1389"#,1390            r#"1391struct Foo {1392    field: u32,1393    field1: u32,1394    field2: u32,1395    field3: u32,1396}1397fn foo(field: u32, field1: u32, val2: u32, val3: u32) -> Foo {1398    Foo {1399        field,1400        field1,1401        field2: val2,1402        field3: val3,1403    }1404}1405fn main() {1406    let bar = 0;1407    let baz = 0;1408    Foo {1409            field: bar,1410            field1: 0,1411            field2: baz,1412            field3: 0,1413        };1414}1415"#,1416        );1417    }14181419    #[test]1420    fn inline_callers_wrapped_in_parentheses() {1421        check_assist(1422            inline_into_callers,1423            r#"1424fn foo$0() -> u32 {1425    let x = 0;1426    x1427}1428fn bar() -> u32 {1429    foo() + foo()1430}1431"#,1432            r#"14331434fn bar() -> u32 {1435    ({1436        let x = 0;1437        x1438    }) + {1439        let x = 0;1440        x1441    }1442}1443"#,1444        )1445    }14461447    #[test]1448    fn inline_call_wrapped_in_parentheses() {1449        check_assist(1450            inline_call,1451            r#"1452fn foo() -> u32 {1453    let x = 0;1454    x1455}1456fn bar() -> u32 {1457    foo$0() + foo()1458}1459"#,1460            r#"1461fn foo() -> u32 {1462    let x = 0;1463    x1464}1465fn bar() -> u32 {1466    ({1467        let x = 0;1468        x1469    }) + foo()1470}1471"#,1472        )1473    }14741475    #[test]1476    fn inline_call_defined_in_macro() {1477        cov_mark::check!(inline_call_defined_in_macro);1478        check_assist(1479            inline_call,1480            r#"1481macro_rules! define_foo {1482    () => { fn foo() -> u32 {1483        let x = 0;1484        x1485    } };1486}1487define_foo!();1488fn bar() -> u32 {1489    foo$0()1490}1491"#,1492            r#"1493macro_rules! define_foo {1494    () => { fn foo() -> u32 {1495        let x = 0;1496        x1497    } };1498}1499define_foo!();1500fn bar() -> u32 {1501    {1502        let x = 0;1503        x1504    }1505}1506"#,1507        )1508    }15091510    #[test]1511    fn inline_call_define_passed_in_macro() {1512        cov_mark::check!(inline_call_defined_in_macro);1513        check_assist(1514            inline_call,1515            r#"1516macro_rules! identity { ($($t:tt)*) => { $($t)* }; }1517identity! {1518    fn htons(hostshort: u16) {1519        let _ = hostshort;1520    }1521}1522fn foo() {1523    htons$0(123)1524}1525"#,1526            r#"1527macro_rules! identity { ($($t:tt)*) => { $($t)* }; }1528identity! {1529    fn htons(hostshort: u16) {1530        let _ = hostshort;1531    }1532}1533fn foo() {1534    {1535        let _ = 123;1536    }1537}1538"#,1539        )1540    }15411542    #[test]1543    fn inline_call_with_self_type() {1544        check_assist(1545            inline_call,1546            r#"1547struct A(u32);1548impl A {1549    fn f() -> Self { Self(114514) }1550}1551fn main() {1552    A::f$0();1553}1554"#,1555            r#"1556struct A(u32);1557impl A {1558    fn f() -> Self { Self(114514) }1559}1560fn main() {1561    A(114514);1562}1563"#,1564        )1565    }15661567    #[test]1568    fn inline_call_with_self_type_but_within_same_impl() {1569        check_assist(1570            inline_call,1571            r#"1572struct A(u32);1573impl A {1574    fn f() -> Self { Self(1919810) }1575    fn main() {1576        Self::f$0();1577    }1578}1579"#,1580            r#"1581struct A(u32);1582impl A {1583    fn f() -> Self { Self(1919810) }1584    fn main() {1585        Self(1919810);1586    }1587}1588"#,1589        )1590    }15911592    #[test]1593    fn local_variable_shadowing_callers_argument() {1594        check_assist(1595            inline_call,1596            r#"1597fn foo(bar: u32, baz: u32) -> u32 {1598    let a = 1;1599    bar * baz * a * 61600}1601fn main() {1602    let a = 7;1603    let b = 1;1604    let res = foo$0(a, b);1605}1606"#,1607            r#"1608fn foo(bar: u32, baz: u32) -> u32 {1609    let a = 1;1610    bar * baz * a * 61611}1612fn main() {1613    let a = 7;1614    let b = 1;1615    let res = {1616        let bar = a;1617        let a = 1;1618        bar * b * a * 61619    };1620}1621"#,1622        );1623    }16241625    #[test]1626    fn async_fn_single_expression() {1627        cov_mark::check!(inline_call_async_fn);1628        check_assist(1629            inline_call,1630            r#"1631async fn bar(x: u32) -> u32 { x + 1 }1632async fn foo(arg: u32) -> u32 {1633    bar(arg).await * 21634}1635fn spawn<T>(_: T) {}1636fn main() {1637    spawn(foo$0(42));1638}1639"#,1640            r#"1641async fn bar(x: u32) -> u32 { x + 1 }1642async fn foo(arg: u32) -> u32 {1643    bar(arg).await * 21644}1645fn spawn<T>(_: T) {}1646fn main() {1647    spawn(async move {1648        bar(42).await * 21649    });1650}1651"#,1652        );1653    }16541655    #[test]1656    fn async_fn_multiple_statements() {1657        cov_mark::check!(inline_call_async_fn);1658        check_assist(1659            inline_call,1660            r#"1661async fn bar(x: u32) -> u32 { x + 1 }1662async fn foo(arg: u32) -> u32 {1663    bar(arg).await;1664    421665}1666fn spawn<T>(_: T) {}1667fn main() {1668    spawn(foo$0(42));1669}1670"#,1671            r#"1672async fn bar(x: u32) -> u32 { x + 1 }1673async fn foo(arg: u32) -> u32 {1674    bar(arg).await;1675    421676}1677fn spawn<T>(_: T) {}1678fn main() {1679    spawn(async move {1680        bar(42).await;1681        421682    });1683}1684"#,1685        );1686    }16871688    #[test]1689    fn async_fn_with_let_statements() {1690        cov_mark::check!(inline_call_async_fn);1691        cov_mark::check!(inline_call_async_fn_with_let_stmts);1692        check_assist(1693            inline_call,1694            r#"1695async fn bar(x: u32) -> u32 { x + 1 }1696async fn foo(x: u32, y: u32, z: &u32) -> u32 {1697    bar(x).await;1698    y + y + *z1699}1700fn spawn<T>(_: T) {}1701fn main() {1702    let var = 42;1703    spawn(foo$0(var, var + 1, &var));1704}1705"#,1706            r#"1707async fn bar(x: u32) -> u32 { x + 1 }1708async fn foo(x: u32, y: u32, z: &u32) -> u32 {1709    bar(x).await;1710    y + y + *z1711}1712fn spawn<T>(_: T) {}1713fn main() {1714    let var = 42;1715    spawn({1716        let y = var + 1;1717        let z: &u32 = &var;1718        async move {1719            bar(var).await;1720            y + y + *z1721        }1722    });1723}1724"#,1725        );1726    }17271728    #[test]1729    fn inline_call_closure_body() {1730        check_assist(1731            inline_call,1732            r#"1733fn f() -> impl Fn() -> i32 {1734    || 21735}17361737fn main() {1738    let _ = $0f()();1739}1740"#,1741            r#"1742fn f() -> impl Fn() -> i32 {1743    || 21744}17451746fn main() {1747    let _ = (|| 2)();1748}1749"#,1750        );1751    }17521753    #[test]1754    fn inline_call_with_multiple_self_types_eq() {1755        check_assist(1756            inline_call,1757            r#"1758#[derive(PartialEq, Eq)]1759enum Enum {1760    A,1761    B,1762}17631764impl Enum {1765    fn a_or_b_eq(&self) -> bool {1766        self == &Self::A || self == &Self::B1767    }1768}17691770fn a() -> bool {1771    Enum::A.$0a_or_b_eq()1772}1773"#,1774            r#"1775#[derive(PartialEq, Eq)]1776enum Enum {1777    A,1778    B,1779}17801781impl Enum {1782    fn a_or_b_eq(&self) -> bool {1783        self == &Self::A || self == &Self::B1784    }1785}17861787fn a() -> bool {1788    {1789        let this = &Enum::A;1790        this == &Enum::A || this == &Enum::B1791    }1792}1793"#,1794        )1795    }17961797    #[test]1798    fn inline_call_with_self_type_in_macros() {1799        check_assist(1800            inline_call,1801            r#"1802trait Trait<T1> {1803    fn f(a: T1) -> Self;1804}18051806macro_rules! impl_from {1807    ($t: ty) => {1808        impl Trait<$t> for $t {1809            fn f(a: $t) -> Self {1810                a as Self1811            }1812        }1813    };1814}18151816struct A {}18171818impl_from!(A);18191820fn main() {1821    let a: A = A{};1822    let b = <A as Trait<A>>::$0f(a);1823}1824"#,1825            r#"1826trait Trait<T1> {1827    fn f(a: T1) -> Self;1828}18291830macro_rules! impl_from {1831    ($t: ty) => {1832        impl Trait<$t> for $t {1833            fn f(a: $t) -> Self {1834                a as Self1835            }1836        }1837    };1838}18391840struct A {}18411842impl_from!(A);18431844fn main() {1845    let a: A = A{};1846    let b = {1847        let a = a;1848        a as A1849    };1850}1851"#,1852        )1853    }18541855    #[test]1856    fn inline_trait_method_call_with_lifetimes() {1857        check_assist(1858            inline_call,1859            r#"1860trait Trait {1861    fn f() -> Self;1862}1863struct Foo<'a>(&'a ());1864impl<'a> Trait for Foo<'a> {1865    fn f() -> Self { Self(&()) }1866}1867impl Foo<'_> {1868    fn new() -> Self {1869        Self::$0f()1870    }1871}1872"#,1873            r#"1874trait Trait {1875    fn f() -> Self;1876}1877struct Foo<'a>(&'a ());1878impl<'a> Trait for Foo<'a> {1879    fn f() -> Self { Self(&()) }1880}1881impl Foo<'_> {1882    fn new() -> Self {1883        Foo(&())1884    }1885}1886"#,1887        )1888    }18891890    #[test]1891    fn method_by_reborrow() {1892        check_assist(1893            inline_call,1894            r#"1895pub struct Foo(usize);18961897impl Foo {1898    fn add1(&mut self) {1899        self.0 += 1;1900    }1901}19021903pub fn main() {1904    let f = &mut Foo(0);1905    f.add1$0();1906}1907"#,1908            r#"1909pub struct Foo(usize);19101911impl Foo {1912    fn add1(&mut self) {1913        self.0 += 1;1914    }1915}19161917pub fn main() {1918    let f = &mut Foo(0);1919    {1920        let this = &mut *f;1921        this.0 += 1;1922    };1923}1924"#,1925        )1926    }19271928    #[test]1929    fn method_by_mut() {1930        check_assist(1931            inline_call,1932            r#"1933pub struct Foo(usize);19341935impl Foo {1936    fn add1(mut self) {1937        self.0 += 1;1938    }1939}19401941pub fn main() {1942    let mut f = Foo(0);1943    f.add1$0();1944}1945"#,1946            r#"1947pub struct Foo(usize);19481949impl Foo {1950    fn add1(mut self) {1951        self.0 += 1;1952    }1953}19541955pub fn main() {1956    let mut f = Foo(0);1957    {1958        let mut this = f;1959        this.0 += 1;1960    };1961}1962"#,1963        )1964    }19651966    #[test]1967    fn inline_call_with_reference_in_macros() {1968        check_assist(1969            inline_call,1970            r#"1971fn _write_u64(s: &mut u64, x: u64) {1972    *s += x;1973}1974macro_rules! impl_write {1975    ($(($ty:ident, $meth:ident),)*) => {$(1976        fn _hash(inner_self_: &u64, state: &mut u64) {1977            $meth(state, *inner_self_)1978        }1979    )*}1980}1981impl_write! { (u64, _write_u64), }1982fn _hash2(self_: &u64, state: &mut u64) {1983    $0_hash(&self_, state);1984}1985"#,1986            r#"1987fn _write_u64(s: &mut u64, x: u64) {1988    *s += x;1989}1990macro_rules! impl_write {1991    ($(($ty:ident, $meth:ident),)*) => {$(1992        fn _hash(inner_self_: &u64, state: &mut u64) {1993            $meth(state, *inner_self_)1994        }1995    )*}1996}1997impl_write! { (u64, _write_u64), }1998fn _hash2(self_: &u64, state: &mut u64) {1999    {2000        let inner_self_: &u64 = &self_;

Code quality findings 29

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
params[0]
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
.expect("NameRef should have had a token.");
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
.expect("editor root should still be a BlockExpr");
Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
body = ast::BlockExpr::cast(body_prettified).unwrap();
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning correctness discarded-result
let _ = $0f()();
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning correctness discarded-result
let _ = (|| 2)();
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.filter_map(|file_ref| match file_ref.name {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let (function, label) = match &call_info.node {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let path = match call.expr()? {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let function = match ctx.sema.resolve_path(&path)? {
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
params.push((param.pat()?, param.ty(), assoc_fn_params.next()?));
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match param.as_local(sema.db) {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.map(|FileReference { name, .. }| match name {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.filter_map(|FileReference { name, .. }| match name {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
sema.ancestors_with_macros(fn_body.syntax().clone()).find_map(ast::Impl::cast)
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
let stripped = t.syntax().text().to_string().replacen(
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
&generic_arg_list.syntax().text().to_string(),
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
t.syntax().clone()
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
func_let_vars.insert(ident_pat.syntax().text().to_string());
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
editor.replace(usage.clone(), this_token.clone());
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
let param_ty = param_ty.clone().map(|param_ty| {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match body.tail_expr() {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
_ => match node
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use super::*;
Info: Direct printing to stdout/stderr. For application logging, prefer using a logging facade like `log` or `tracing` for better control over levels, formatting, and output destinations.
info maintainability println-macro
println!("Hello, {}!", name);
Info: Use of raw pointers (*const T, *mut T) typically requires 'unsafe' blocks for dereferencing. Ensure usage is justified (FFI, low-level optimizations) and memory safety is manually upheld.
info safety raw-pointer
fn foo(x: *const u32) -> u32 {
Info: Use of raw pointers (*const T, *mut T) typically requires 'unsafe' blocks for dereferencing. Ensure usage is justified (FFI, low-level optimizations) and memory safety is manually upheld.
info safety raw-pointer
fn foo(x: *const u32) -> u32 {
Info: Use of raw pointers (*const T, *mut T) typically requires 'unsafe' blocks for dereferencing. Ensure usage is justified (FFI, low-level optimizations) and memory safety is manually upheld.
info safety raw-pointer
let x: *const u32 = &222;

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.

Generated by searchcode.com · powered by code_get_file + code_get_findings