src/tools/rust-analyzer/crates/ide/src/goto_definition.rs RUST 4,260 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,260.
1use std::{iter, mem::discriminant};23use crate::Analysis;4use crate::{5    FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,6    doc_links::token_as_doc_comment,7    navigation_target::{self, ToNav},8};9use hir::{10    AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,11};12use ide_db::ra_fixture::{RaFixtureConfig, UpmapFromRaFixture};13use ide_db::{14    RootDatabase, SymbolKind,15    base_db::{AnchoredPath, SourceDatabase},16    defs::{Definition, IdentClass},17    famous_defs::FamousDefs,18    helpers::pick_best_token,19    syntax_helpers::node_ext::find_loops,20};21use itertools::Itertools;22use span::FileId;23use syntax::{24    AstNode, AstToken, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange, ast, match_ast,25};2627#[derive(Debug)]28pub struct GotoDefinitionConfig<'a> {29    pub ra_fixture: RaFixtureConfig<'a>,30}3132// Feature: Go to Definition33//34// Navigates to the definition of an identifier.35//36// For outline modules, this will navigate to the source file of the module.37//38// | Editor  | Shortcut |39// |---------|----------|40// | VS Code | <kbd>F12</kbd> |41//42// ![Go to Definition](https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif)43//44// #### Special Go to Definitions45//46// You can go to definition on operators and keywords as well. The behavior goes as follows:47//48//  - On overloadable operators, this will take you to the `impl` of the operator's trait for this type, or to the trait if49//    the impl cannot be determined.50//  - For `?` on `Result` that goes through a non-trivial `From` (i.e. not the blanket `impl<T> From<T> for T`), it'll take51//    you to the `From` impl.52//  - On control flow keywords (loops, conditions, etc.) and `fn`, it'll take you to all exit points for this construct53//    or its entrance, the opposite of the keyword you're at (e.g. on `fn` it'll take you to all exit points, and on `return`54//    it'll take you to the `fn`).55//  - It'll skip known blanket impls from the standard library where possible. For example, on a `try_into()` that comes56//    from the blanket `impl<T: TryFrom<U>, U> TryInto<T> for U`, it'll take you to the `TryFrom` impl, and if it also57//    comes from the blanket `impl<T: From<U>, U> TryFrom<U> for T`, it'll take you to the `From` impl.58pub(crate) fn goto_definition(59    db: &RootDatabase,60    FilePosition { file_id, offset }: FilePosition,61    config: &GotoDefinitionConfig<'_>,62) -> Option<RangeInfo<Vec<NavigationTarget>>> {63    let sema = &Semantics::new(db);64    let file = sema.parse_guess_edition(file_id).syntax().clone();65    let edition = sema.attach_first_edition(file_id).edition(db);66    let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {67        IDENT68        | INT_NUMBER69        | LIFETIME_IDENT70        | T![self]71        | T![super]72        | T![crate]73        | T![Self]74        | COMMENT75        | INNER_DOC_COMMENT76        | OUTER_DOC_COMMENT => 4,77        // index and prefix ops78        T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,79        kind if kind.is_keyword(edition) => 2,80        T!['('] | T![')'] => 2,81        kind if kind.is_trivia() => 0,82        _ => 1,83    })?;84    if let Some(doc_comment) = token_as_doc_comment(&original_token) {85        return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| {86            let nav = def.try_to_nav(sema)?;87            Some(RangeInfo::new(link_range, nav.collect()))88        });89    }9091    if let Some((range, _, _, resolution)) =92        sema.check_for_format_args_template(original_token.clone(), offset)93    {94        return Some(RangeInfo::new(95            range,96            match resolution {97                Some(res) => def_to_nav(sema, Definition::from(res)),98                None => vec![],99            },100        ));101    }102103    if let Some(navs) = handle_control_flow_keywords(sema, &original_token) {104        return Some(RangeInfo::new(original_token.text_range(), navs));105    }106107    let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);108    let mut navs = Vec::new();109    for token in tokens {110        if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {111            navs.extend(n);112            continue;113        }114115        if let Some(n) = find_definition_for_comparison_operators(sema, &token.value) {116            navs.extend(n);117            continue;118        }119120        let parent = token.value.parent()?;121122        if let Some(question_mark_conversion) = goto_question_mark_conversions(sema, &parent) {123            navs.extend(def_to_nav(sema, question_mark_conversion.into()));124            continue;125        }126127        if let Some(token) = ast::String::cast(token.value.clone())128            && let Some(original_token) = ast::String::cast(original_token.clone())129            && let Some((analysis, fixture_analysis)) =130                Analysis::from_ra_fixture(sema, original_token, &token, &config.ra_fixture)131            && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)132        {133            return hir::attach_db_allow_change(&analysis.db, || {134                goto_definition(135                    &analysis.db,136                    FilePosition { file_id: virtual_file_id, offset: file_offset },137                    config,138                )139            })140            .and_then(|navs| {141                navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()142            });143        }144145        let token_file_id = token.file_id;146        if let Some(token) = ast::String::cast(token.value.clone())147            && let Some(x) =148                try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)149        {150            navs.push(x);151            continue;152        }153154        if ast::TokenTree::can_cast(parent.kind())155            && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)156        {157            navs.push(x);158            continue;159        }160161        let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };162        navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {163            if let Definition::ExternCrateDecl(crate_def) = def {164                return crate_def165                    .resolved_crate(db)166                    .map(|it| it.root_module(db).to_nav(db))167                    .into_iter()168                    .flatten()169                    .collect();170            }171            try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))172        }));173    }174    let navs = navs.into_iter().unique().collect();175176    Some(RangeInfo::new(original_token.text_range(), navs))177}178179/// When the `?` operator is used on `Result`, go to the `From` impl if it exists as this provides more value.180fn goto_question_mark_conversions(181    sema: &Semantics<'_, RootDatabase>,182    node: &SyntaxNode,183) -> Option<hir::Function> {184    let node = ast::TryExpr::cast(node.clone())?;185    let try_expr_ty = sema.type_of_expr(&node.expr()?)?.adjusted();186187    let fd = FamousDefs(sema, try_expr_ty.krate(sema.db));188    let result_enum = fd.core_result_Result()?.into();189190    let (try_expr_ty_adt, try_expr_ty_args) = try_expr_ty.as_adt_with_args()?;191    if try_expr_ty_adt != result_enum {192        // FIXME: Support `Poll<Result>`.193        return None;194    }195    let original_err_ty = try_expr_ty_args.get(1)?.clone()?;196197    let returned_ty = sema.try_expr_returned_type(&node)?;198    let (returned_adt, returned_ty_args) = returned_ty.as_adt_with_args()?;199    if returned_adt != result_enum {200        return None;201    }202    let returned_err_ty = returned_ty_args.get(1)?.clone()?;203204    if returned_err_ty.could_unify_with_deeply(sema.db, &original_err_ty) {205        return None;206    }207208    let from_trait = fd.core_convert_From()?;209    let from_fn = from_trait.function(sema.db, sym::from)?;210    sema.resolve_trait_impl_method(211        returned_err_ty.clone(),212        from_trait,213        from_fn,214        [returned_err_ty, original_err_ty],215    )216}217218// If the token is into(), try_into(), search the definition of From, TryFrom.219fn find_definition_for_known_blanket_dual_impls(220    sema: &Semantics<'_, RootDatabase>,221    original_token: &SyntaxToken,222) -> Option<Vec<NavigationTarget>> {223    let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;224    let callable = sema.resolve_method_call_as_callable(&method_call)?;225    let CallableKind::Function(f) = callable.kind() else { return None };226    let assoc = f.as_assoc_item(sema.db)?;227228    let return_type = callable.return_type();229    let fd = FamousDefs(sema, return_type.krate(sema.db));230231    let t = match assoc.container(sema.db) {232        hir::AssocItemContainer::Trait(t) => t,233        hir::AssocItemContainer::Impl(impl_)234            if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>235        {236            let t = fd.core_convert_FromStr()?;237            let t_f = t.function(sema.db, &sym::from_str)?;238            return sema239                .resolve_trait_impl_method(240                    return_type.clone(),241                    t,242                    t_f,243                    [return_type.type_arguments().next()?],244                )245                .map(|f| def_to_nav(sema, f.into()));246        }247        hir::AssocItemContainer::Impl(_) => return None,248    };249250    let fn_name = f.name(sema.db);251    let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {252        let dual = fd.core_convert_From()?;253        let dual_f = dual.function(sema.db, &sym::from)?;254        sema.resolve_trait_impl_method(255            return_type.clone(),256            dual,257            dual_f,258            [return_type, callable.receiver_param(sema.db)?.1],259        )?260    } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {261        let dual = fd.core_convert_TryFrom()?;262        let dual_f = dual.function(sema.db, &sym::try_from)?;263        sema.resolve_trait_impl_method(264            return_type.clone(),265            dual,266            dual_f,267            // Extract the `T` from `Result<T, ..>`268            [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],269        )?270    } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {271        let dual = fd.core_fmt_Display()?;272        let dual_f = dual.function(sema.db, &sym::fmt)?;273        sema.resolve_trait_impl_method(274            return_type.clone(),275            dual,276            dual_f,277            [callable.receiver_param(sema.db)?.1.strip_reference()],278        )?279    } else {280        return None;281    };282    // Assert that we got a trait impl function, if we are back in a trait definition we didn't283    // succeed284    let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;285    let def = Definition::from(f);286    Some(def_to_nav(sema, def))287}288289// If the token is a comparison operator (!=, <, <=, >, >=) that resolves to a default trait method, navigate to the corresponding primary method (eq for ne, partial_cmp for the others).290fn find_definition_for_comparison_operators(291    sema: &Semantics<'_, RootDatabase>,292    original_token: &SyntaxToken,293) -> Option<Vec<NavigationTarget>> {294    let bin_expr = ast::BinExpr::cast(original_token.parent()?)?;295296    let f = sema.resolve_bin_expr(&bin_expr)?;297    let assoc = f.as_assoc_item(sema.db)?;298299    let lhs_type = sema.type_of_expr(&bin_expr.lhs()?)?.original;300    let rhs_type = sema.type_of_expr(&bin_expr.rhs()?)?.original;301302    let t = match assoc.container(sema.db) {303        hir::AssocItemContainer::Trait(t) => t,304        hir::AssocItemContainer::Impl(_) => return None, // Already implemented by the type305    };306307    let fn_name = f.name(sema.db);308    let fn_name_str = fn_name.as_str();309310    let trait_name = t.name(sema.db);311    let trait_name_str = trait_name.as_str();312313    let (target_fn_name, expected_trait) = match fn_name_str {314        "ne" => ("eq", "PartialEq"),315        "lt" | "le" | "gt" | "ge" => ("partial_cmp", "PartialOrd"),316        _ => return None,317    };318319    if trait_name_str != expected_trait {320        return None;321    }322323    let primary_f = t.items(sema.db).into_iter().find_map(|item| {324        if let hir::AssocItem::Function(func) = item325            && func.name(sema.db).as_str() == target_fn_name326        {327            return Some(func);328        }329        None330    })?;331332    // Chalk requires ALL trait substitutions, including `Self`!333    // We must pass [Self, Rhs]334    let resolved_f = sema.resolve_trait_impl_method(335        lhs_type.clone(),336        t,337        primary_f,338        [lhs_type.clone(), rhs_type.clone()],339    )?;340341    let def = Definition::from(resolved_f);342343    Some(def_to_nav(sema, def))344}345fn try_lookup_include_path(346    sema: &Semantics<'_, RootDatabase>,347    token: InFile<ast::String>,348    file_id: FileId,349) -> Option<NavigationTarget> {350    let file = token.file_id.macro_file()?;351352    // Check that we are in the eager argument expansion of an include macro353    // that is we are the string input of it354    if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file())355        .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none())356    {357        return None;358    }359    let path = token.value.value().ok()?;360361    let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;362    let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?;363    Some(NavigationTarget {364        file_id,365        full_range: TextRange::new(0.into(), size),366        name: hir::Symbol::intern(&path),367        alias: None,368        focus_range: None,369        kind: None,370        container_name: None,371        description: None,372    })373}374375fn try_lookup_macro_def_in_macro_use(376    sema: &Semantics<'_, RootDatabase>,377    token: SyntaxToken,378) -> Option<NavigationTarget> {379    let extern_crate = token.parent()?.ancestors().find_map(ast::ExternCrate::cast)?;380    let extern_crate = sema.to_def(&extern_crate)?;381    let krate = extern_crate.resolved_crate(sema.db)?;382383    for mod_def in krate.root_module(sema.db).declarations(sema.db) {384        if let ModuleDef::Macro(mac) = mod_def385            && mac.name(sema.db).as_str() == token.text()386            && let Some(nav) = mac.try_to_nav(sema)387        {388            return Some(nav.call_site);389        }390    }391392    None393}394395/// finds the trait definition of an impl'd item, except function396/// e.g.397/// ```rust398/// trait A { type a; }399/// struct S;400/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait401/// ```402fn try_filter_trait_item_definition(403    sema: &Semantics<'_, RootDatabase>,404    def: &Definition<'_>,405) -> Option<Vec<NavigationTarget>> {406    let db = sema.db;407    let assoc = def.as_assoc_item(db)?;408    match assoc {409        AssocItem::Function(..) => None,410        AssocItem::Const(..) | AssocItem::TypeAlias(..) => {411            let trait_ = assoc.implemented_trait(db)?;412            let name = def.name(db)?;413            let discriminant_value = discriminant(&assoc);414            trait_415                .items(db)416                .iter()417                .filter(|itm| discriminant(*itm) == discriminant_value)418                .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(sema)).flatten())419                .map(|it| it.collect())420        }421    }422}423424fn handle_control_flow_keywords(425    sema: &Semantics<'_, RootDatabase>,426    token: &SyntaxToken,427) -> Option<Vec<NavigationTarget>> {428    match token.kind() {429        // For `fn` / `loop` / `while` / `for` / `async` / `match`, return the keyword it self,430        // so that VSCode will find the references when using `ctrl + click`431        T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),432        T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),433        T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {434            nav_for_break_points(sema, token)435        }436        T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),437        _ => None,438    }439}440441pub(crate) fn find_fn_or_blocks(442    sema: &Semantics<'_, RootDatabase>,443    token: &SyntaxToken,444) -> Vec<SyntaxNode> {445    let find_ancestors = |token: SyntaxToken| {446        let token_kind = token.kind();447448        for anc in sema.token_ancestors_with_macros(token) {449            let node = match_ast! {450                match anc {451                    ast::Fn(fn_) => fn_.syntax().clone(),452                    ast::ClosureExpr(c) => c.syntax().clone(),453                    ast::BlockExpr(blk) => {454                        match blk.modifier() {455                            Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),456                            Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),457                            _ => continue,458                        }459                    },460                    _ => continue,461                }462            };463464            return Some(node);465        }466        None467    };468469    sema.descend_into_macros(token.clone()).into_iter().filter_map(find_ancestors).collect_vec()470}471472fn nav_for_exit_points(473    sema: &Semantics<'_, RootDatabase>,474    token: &SyntaxToken,475) -> Option<Vec<NavigationTarget>> {476    let db = sema.db;477    let token_kind = token.kind();478479    let navs = find_fn_or_blocks(sema, token)480        .into_iter()481        .filter_map(|node| {482            let file_id = sema.hir_file_for(&node);483484            match_ast! {485                match node {486                    ast::Fn(fn_) => {487                        let mut nav = sema.to_def(&fn_)?.try_to_nav(sema)?;488                        // For async token, we navigate to itself, which triggers489                        // VSCode to find the references490                        let focus_token = if matches!(token_kind, T![async]) {491                            fn_.async_token()?492                        } else {493                            fn_.fn_token()?494                        };495496                        let focus_frange = InFile::new(file_id, focus_token.text_range())497                            .original_node_file_range_opt(db)498                            .map(|(frange, _)| frange);499500                        if let Some(FileRange { file_id, range }) = focus_frange {501                            let contains_frange = |nav: &NavigationTarget| {502                                nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range)503                            };504505                            if let Some(def_site) = nav.def_site.as_mut() {506                                if contains_frange(def_site) {507                                    def_site.focus_range = Some(range);508                                }509                            } else if contains_frange(&nav.call_site) {510                                nav.call_site.focus_range = Some(range);511                            }512                        }513514                        Some(nav)515                    },516                    ast::ClosureExpr(c) => {517                        let pipe_tok = c.param_list().and_then(|it| it.pipe_token())?.text_range();518                        let closure_in_file = InFile::new(file_id, c.into());519                        Some(expr_to_nav(db, closure_in_file, Some(pipe_tok)))520                    },521                    ast::BlockExpr(blk) => {522                        match blk.modifier() {523                            Some(ast::BlockModifier::Async(_)) => {524                                let async_tok = blk.async_token()?.text_range();525                                let blk_in_file = InFile::new(file_id, blk.into());526                                Some(expr_to_nav(db, blk_in_file, Some(async_tok)))527                            },528                            Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => {529                                let try_tok = blk.try_block_modifier()?.try_token()?.text_range();530                                let blk_in_file = InFile::new(file_id, blk.into());531                                Some(expr_to_nav(db, blk_in_file, Some(try_tok)))532                            },533                            _ => None,534                        }535                    },536                    _ => None,537                }538            }539        })540        .flatten()541        .collect_vec();542543    Some(navs)544}545546pub(crate) fn find_branch_root(547    sema: &Semantics<'_, RootDatabase>,548    token: &SyntaxToken,549) -> Vec<SyntaxNode> {550    let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {551        sema.descend_into_macros(token.clone())552            .into_iter()553            .filter_map(|token| node_filter(token.parent()?))554            .collect_vec()555    };556557    match token.kind() {558        T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),559        T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),560        T![if] => find_nodes(|node| {561            let if_expr = ast::IfExpr::cast(node)?;562563            let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {564                let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;565                let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {566                    return None;567                };568569                (else_branch.syntax() == if_expr.syntax()).then_some(parent_if)570            })571            .last()?;572573            Some(root_if.syntax().clone())574        }),575        _ => vec![],576    }577}578579fn nav_for_branch_exit_points(580    sema: &Semantics<'_, RootDatabase>,581    token: &SyntaxToken,582) -> Option<Vec<NavigationTarget>> {583    let db = sema.db;584585    let navs = match token.kind() {586        T![match] => find_branch_root(sema, token)587            .into_iter()588            .filter_map(|node| {589                let file_id = sema.hir_file_for(&node);590                let match_expr = ast::MatchExpr::cast(node)?;591                let focus_range = match_expr.match_token()?.text_range();592                let match_expr_in_file = InFile::new(file_id, match_expr.into());593                Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))594            })595            .flatten()596            .collect_vec(),597598        T![=>] => find_branch_root(sema, token)599            .into_iter()600            .filter_map(|node| {601                let match_arm = ast::MatchArm::cast(node)?;602                let match_expr = sema603                    .ancestors_with_macros(match_arm.syntax().clone())604                    .find_map(ast::MatchExpr::cast)?;605                let file_id = sema.hir_file_for(match_expr.syntax());606                let focus_range = match_arm.fat_arrow_token()?.text_range();607                let match_expr_in_file = InFile::new(file_id, match_expr.into());608                Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))609            })610            .flatten()611            .collect_vec(),612613        T![if] => find_branch_root(sema, token)614            .into_iter()615            .filter_map(|node| {616                let file_id = sema.hir_file_for(&node);617                let if_expr = ast::IfExpr::cast(node)?;618                let focus_range = if_expr.if_token()?.text_range();619                let if_expr_in_file = InFile::new(file_id, if_expr.into());620                Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))621            })622            .flatten()623            .collect_vec(),624625        _ => return Some(Vec::new()),626    };627628    Some(navs)629}630631fn nav_for_break_points(632    sema: &Semantics<'_, RootDatabase>,633    token: &SyntaxToken,634) -> Option<Vec<NavigationTarget>> {635    let db = sema.db;636637    let navs = find_loops(sema, token)?638        .filter_map(|expr| {639            let file_id = sema.hir_file_for(expr.syntax());640            let expr_in_file = InFile::new(file_id, expr.clone());641            let focus_range = match expr {642                ast::Expr::LoopExpr(loop_) => loop_.loop_token()?.text_range(),643                ast::Expr::WhileExpr(while_) => while_.while_token()?.text_range(),644                ast::Expr::ForExpr(for_) => for_.for_token()?.text_range(),645                // We guarantee that the label exists646                ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),647                _ => return None,648            };649            let nav = expr_to_nav(db, expr_in_file, Some(focus_range));650            Some(nav)651        })652        .flatten()653        .collect_vec();654655    Some(navs)656}657658fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition<'_>) -> Vec<NavigationTarget> {659    def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default()660}661662fn expr_to_nav(663    db: &RootDatabase,664    InFile { file_id, value }: InFile<ast::Expr>,665    focus_range: Option<TextRange>,666) -> UpmappingResult<NavigationTarget> {667    let kind = SymbolKind::Label;668669    let value_range = value.syntax().text_range();670    let navs = navigation_target::orig_range_with_focus_r(db, file_id, value_range, focus_range);671    navs.map(|(hir::FileRangeWrapper { file_id, range }, focus_range)| {672        NavigationTarget::from_syntax(673            file_id,674            hir::Symbol::intern("<expr>"),675            focus_range,676            range,677            kind,678        )679    })680}681682#[cfg(test)]683mod tests {684    use crate::{GotoDefinitionConfig, fixture};685    use ide_db::{FileRange, ra_fixture::RaFixtureConfig};686    use itertools::Itertools;687688    const TEST_CONFIG: GotoDefinitionConfig<'_> =689        GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };690691    #[track_caller]692    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {693        let (analysis, position, expected) = fixture::annotations(ra_fixture);694        let navs = analysis695            .goto_definition(position, &TEST_CONFIG)696            .unwrap()697            .expect("no definition found")698            .info;699700        let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());701        let navs = navs702            .into_iter()703            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })704            .sorted_by_key(cmp)705            .collect::<Vec<_>>();706        let expected = expected707            .into_iter()708            .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })709            .sorted_by_key(cmp)710            .collect::<Vec<_>>();711712        assert_eq!(expected, navs);713    }714715    fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {716        let (analysis, position) = fixture::position(ra_fixture);717        let navs = analysis718            .goto_definition(position, &TEST_CONFIG)719            .unwrap()720            .expect("no definition found")721            .info;722723        assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")724    }725726    #[track_caller]727    fn check_no_definition(#[rust_analyzer::rust_fixture] ra_fixture: &str) {728        let (analysis, position) = fixture::position(ra_fixture);729        let navs = analysis.goto_definition(position, &TEST_CONFIG).unwrap();730        assert!(navs.is_none(), "didn't expect this to resolve anywhere: {navs:?}");731    }732733    fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {734        let (analysis, position, _) = fixture::annotations(ra_fixture);735        let navs = analysis736            .goto_definition(position, &TEST_CONFIG)737            .unwrap()738            .expect("no definition found")739            .info;740        assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());741        let Some(target) = navs.into_iter().next() else {742            panic!("expected single navigation target but encountered none");743        };744        assert_eq!(target.name, hir::Symbol::intern(expected_name));745    }746747    #[test]748    fn goto_def_pat_range_to_inclusive() {749        check_name(750            "RangeToInclusive",751            r#"752//- minicore: range753fn f(ch: char) -> bool {754    match ch {755        ..$0='z' => true,756        _ => false757    }758}759"#,760        );761    }762763    #[test]764    fn goto_def_pat_range_to() {765        check_name(766            "RangeTo",767            r#"768//- minicore: range769fn f(ch: char) -> bool {770    match ch {771        .$0.'z' => true,772        _ => false773    }774}775"#,776        );777    }778779    #[test]780    fn goto_def_pat_range() {781        check_name(782            "Range",783            r#"784//- minicore: range785fn f(ch: char) -> bool {786    match ch {787        'a'.$0.'z' => true,788        _ => false789    }790}791"#,792        );793    }794795    #[test]796    fn goto_def_pat_range_inclusive() {797        check_name(798            "RangeInclusive",799            r#"800//- minicore: range801fn f(ch: char) -> bool {802    match ch {803        'a'..$0='z' => true,804        _ => false805    }806}807"#,808        );809    }810811    #[test]812    fn goto_def_pat_range_from() {813        check_name(814            "RangeFrom",815            r#"816//- minicore: range817fn f(ch: char) -> bool {818    match ch {819        'a'..$0 => true,820        _ => false821    }822}823"#,824        );825    }826827    #[test]828    fn goto_def_expr_range() {829        check_name(830            "Range",831            r#"832//- minicore: range833let x = 0.$0.1;834"#,835        );836    }837838    #[test]839    fn goto_def_expr_range_from() {840        check_name(841            "RangeFrom",842            r#"843//- minicore: range844fn f(arr: &[i32]) -> &[i32] {845    &arr[0.$0.]846}847"#,848        );849    }850851    #[test]852    fn goto_def_expr_range_inclusive() {853        check_name(854            "RangeInclusive",855            r#"856//- minicore: range857let x = 0.$0.=1;858"#,859        );860    }861862    #[test]863    fn goto_def_expr_range_full() {864        check_name(865            "RangeFull",866            r#"867//- minicore: range868fn f(arr: &[i32]) -> &[i32] {869    &arr[.$0.]870}871"#,872        );873    }874875    #[test]876    fn goto_def_expr_range_to() {877        check_name(878            "RangeTo",879            r#"880//- minicore: range881fn f(arr: &[i32]) -> &[i32] {882    &arr[.$0.10]883}884"#,885        );886    }887888    #[test]889    fn goto_def_expr_range_to_inclusive() {890        check_name(891            "RangeToInclusive",892            r#"893//- minicore: range894fn f(arr: &[i32]) -> &[i32] {895    &arr[.$0.=10]896}897"#,898        );899    }900901    #[test]902    fn goto_def_in_included_file() {903        check(904            r#"905//- minicore:include906//- /main.rs907908include!("a.rs");909910fn main() {911    foo();912}913914//- /a.rs915fn func_in_include() {916 //^^^^^^^^^^^^^^^917}918919fn foo() {920    func_in_include$0();921}922"#,923        );924    }925926    #[test]927    fn goto_def_in_included_file_nested() {928        check(929            r#"930//- minicore:include931//- /main.rs932933macro_rules! passthrough {934    ($($tt:tt)*) => { $($tt)* }935}936937passthrough!(include!("a.rs"));938939fn main() {940    foo();941}942943//- /a.rs944fn func_in_include() {945 //^^^^^^^^^^^^^^^946}947948fn foo() {949    func_in_include$0();950}951"#,952        );953    }954955    #[test]956    fn goto_def_in_included_file_inside_mod() {957        check(958            r#"959//- minicore:include960//- /main.rs961mod a {962    include!("b.rs");963}964//- /b.rs965fn func_in_include() {966 //^^^^^^^^^^^^^^^967}968fn foo() {969    func_in_include$0();970}971"#,972        );973974        check(975            r#"976//- minicore:include977//- /main.rs978mod a {979    include!("a.rs");980}981//- /a.rs982fn func_in_include() {983 //^^^^^^^^^^^^^^^984}985986fn foo() {987    func_in_include$0();988}989"#,990        );991    }992993    #[test]994    fn goto_def_if_items_same_name() {995        check(996            r#"997trait Trait {998    type A;999    const A: i32;1000        //^1001}10021003struct T;1004impl Trait for T {1005    type A = i32;1006    const A$0: i32 = -9;1007}"#,1008        );1009    }10101011    #[test]1012    fn goto_def_array_length_prefers_value_namespace() {1013        check(1014            r#"1015struct N;10161017trait Trait {}10181019impl<const N: usize> Trait for [N; N$0] {}1020         //^1021"#,1022        );1023    }10241025    #[test]1026    fn goto_def_in_mac_call_in_attr_invoc() {1027        check(1028            r#"1029//- proc_macros: identity1030pub struct Struct {1031        // ^^^^^^1032    field: i32,1033}10341035macro_rules! identity {1036    ($($tt:tt)*) => {$($tt)*};1037}10381039#[proc_macros::identity]1040fn function() {1041    identity!(Struct$0 { field: 0 });1042}10431044"#,1045        )1046    }10471048    #[test]1049    fn goto_def_for_extern_crate() {1050        check(1051            r#"1052//- /main.rs crate:main deps:std1053extern crate std$0;1054//- /std/lib.rs crate:std1055// empty1056//^file1057"#,1058        )1059    }10601061    #[test]1062    fn goto_def_for_renamed_extern_crate() {1063        check(1064            r#"1065//- /main.rs crate:main deps:std1066extern crate std as abc$0;1067//- /std/lib.rs crate:std1068// empty1069//^file1070"#,1071        )1072    }10731074    #[test]1075    fn goto_def_in_items() {1076        check(1077            r#"1078struct Foo;1079     //^^^1080enum E { X(Foo$0) }1081"#,1082        );1083    }10841085    #[test]1086    fn goto_def_at_start_of_item() {1087        check(1088            r#"1089struct Foo;1090     //^^^1091enum E { X($0Foo) }1092"#,1093        );1094    }10951096    #[test]1097    fn goto_definition_resolves_correct_name() {1098        check(1099            r#"1100//- /lib.rs1101use a::Foo;1102mod a;1103mod b;1104enum E { X(Foo$0) }11051106//- /a.rs1107pub struct Foo;1108         //^^^1109//- /b.rs1110pub struct Foo;1111"#,1112        );1113    }11141115    #[test]1116    fn goto_def_for_module_declaration() {1117        check(1118            r#"1119//- /lib.rs1120mod $0foo;11211122//- /foo.rs1123// empty1124//^file1125"#,1126        );11271128        check(1129            r#"1130//- /lib.rs1131mod $0foo;11321133//- /foo/mod.rs1134// empty1135//^file1136"#,1137        );1138    }11391140    #[test]1141    fn goto_def_for_macros() {1142        check(1143            r#"1144macro_rules! foo { () => { () } }1145           //^^^1146fn bar() {1147    $0foo!();1148}1149"#,1150        );1151    }11521153    #[test]1154    fn goto_def_for_macros_from_other_crates() {1155        check(1156            r#"1157//- /lib.rs crate:main deps:foo1158use foo::foo;1159fn bar() {1160    $0foo!();1161}11621163//- /foo/lib.rs crate:foo1164#[macro_export]1165macro_rules! foo { () => { () } }1166           //^^^1167"#,1168        );1169    }11701171    #[test]1172    fn goto_def_for_macros_in_use_tree() {1173        check(1174            r#"1175//- /lib.rs crate:main deps:foo1176use foo::foo$0;11771178//- /foo/lib.rs crate:foo1179#[macro_export]1180macro_rules! foo { () => { () } }1181           //^^^1182"#,1183        );1184    }11851186    #[test]1187    fn goto_def_for_macro_defined_fn_with_arg() {1188        check(1189            r#"1190//- /lib.rs1191macro_rules! define_fn {1192    ($name:ident) => (fn $name() {})1193}11941195define_fn!(foo);1196         //^^^11971198fn bar() {1199   $0foo();1200}1201"#,1202        );1203    }12041205    #[test]1206    fn goto_def_for_macro_defined_fn_no_arg() {1207        check(1208            r#"1209//- /lib.rs1210macro_rules! define_fn {1211    () => (fn foo() {})1212            //^^^1213}12141215  define_fn!();1216//^^^^^^^^^^1217fn bar() {1218   $0foo();1219}1220"#,1221        );1222    }12231224    #[test]1225    fn goto_definition_works_for_macro_inside_pattern() {1226        check(1227            r#"1228//- /lib.rs1229macro_rules! foo {() => {0}}1230           //^^^12311232fn bar() {1233    match (0,1) {1234        ($0foo!(), _) => {}1235    }1236}1237"#,1238        );1239    }12401241    #[test]1242    fn goto_definition_works_for_macro_inside_match_arm_lhs() {1243        check(1244            r#"1245//- /lib.rs1246macro_rules! foo {() => {0}}1247           //^^^1248fn bar() {1249    match 0 {1250        $0foo!() => {}1251    }1252}1253"#,1254        );1255    }12561257    #[test]1258    fn goto_definition_works_for_consts_inside_range_pattern() {1259        check(1260            r#"1261//- /lib.rs1262const A: u32 = 0;1263    //^12641265fn bar(v: u32) {1266    match v {1267        0..=$0A => {}1268        _ => {}1269    }1270}1271"#,1272        );1273    }12741275    #[test]1276    fn goto_def_for_use_alias() {1277        check(1278            r#"1279//- /lib.rs crate:main deps:foo1280use foo as bar$0;12811282//- /foo/lib.rs crate:foo1283// empty1284//^file1285"#,1286        );1287    }12881289    #[test]1290    fn goto_def_for_use_alias_foo_macro() {1291        check(1292            r#"1293//- /lib.rs crate:main deps:foo1294use foo::foo as bar$0;12951296//- /foo/lib.rs crate:foo1297#[macro_export]1298macro_rules! foo { () => { () } }1299           //^^^1300"#,1301        );1302    }13031304    #[test]1305    fn goto_def_for_methods() {1306        check(1307            r#"1308struct Foo;1309impl Foo {1310    fn frobnicate(&self) { }1311     //^^^^^^^^^^1312}13131314fn bar(foo: &Foo) {1315    foo.frobnicate$0();1316}1317"#,1318        );1319    }13201321    #[test]1322    fn goto_def_for_fields() {1323        check(1324            r#"1325struct Foo {1326    spam: u32,1327} //^^^^13281329fn bar(foo: &Foo) {1330    foo.spam$0;1331}1332"#,1333        );1334    }13351336    #[test]1337    fn goto_def_for_record_fields() {1338        check(1339            r#"1340//- /lib.rs1341struct Foo {1342    spam: u32,1343} //^^^^13441345fn bar() -> Foo {1346    Foo {1347        spam$0: 0,1348    }1349}1350"#,1351        );1352    }13531354    #[test]1355    fn goto_def_for_record_pat_fields() {1356        check(1357            r#"1358//- /lib.rs1359struct Foo {1360    spam: u32,1361} //^^^^13621363fn bar(foo: Foo) -> Foo {1364    let Foo { spam$0: _, } = foo1365}1366"#,1367        );1368    }13691370    #[test]1371    fn goto_def_for_record_fields_macros() {1372        check(1373            r"1374macro_rules! m { () => { 92 };}1375struct Foo { spam: u32 }1376           //^^^^13771378fn bar() -> Foo {1379    Foo { spam$0: m!() }1380}1381",1382        );1383    }13841385    #[test]1386    fn goto_for_tuple_fields() {1387        check(1388            r#"1389struct Foo(u32);1390         //^^^13911392fn bar() {1393    let foo = Foo(0);1394    foo.$00;1395}1396"#,1397        );1398    }13991400    #[test]1401    fn goto_def_for_ufcs_inherent_methods() {1402        check(1403            r#"1404struct Foo;1405impl Foo {1406    fn frobnicate() { }1407}    //^^^^^^^^^^14081409fn bar(foo: &Foo) {1410    Foo::frobnicate$0();1411}1412"#,1413        );1414    }14151416    #[test]1417    fn goto_def_for_ufcs_trait_methods_through_traits() {1418        check(1419            r#"1420trait Foo {1421    fn frobnicate();1422}    //^^^^^^^^^^14231424fn bar() {1425    Foo::frobnicate$0();1426}1427"#,1428        );1429    }14301431    #[test]1432    fn goto_def_for_ufcs_trait_methods_through_self() {1433        check(1434            r#"1435struct Foo;1436trait Trait {1437    fn frobnicate();1438}    //^^^^^^^^^^1439impl Trait for Foo {}14401441fn bar() {1442    Foo::frobnicate$0();1443}1444"#,1445        );1446    }14471448    #[test]1449    fn goto_definition_on_self() {1450        check(1451            r#"1452struct Foo;1453impl Foo {1454   //^^^1455    pub fn new() -> Self {1456        Self$0 {}1457    }1458}1459"#,1460        );1461        check(1462            r#"1463struct Foo;1464impl Foo {1465   //^^^1466    pub fn new() -> Self$0 {1467        Self {}1468    }1469}1470"#,1471        );14721473        check(1474            r#"1475enum Foo { A }1476impl Foo {1477   //^^^1478    pub fn new() -> Self$0 {1479        Foo::A1480    }1481}1482"#,1483        );14841485        check(1486            r#"1487enum Foo { A }1488impl Foo {1489   //^^^1490    pub fn thing(a: &Self$0) {1491    }1492}1493"#,1494        );1495    }14961497    #[test]1498    fn goto_definition_on_self_in_trait_impl() {1499        check(1500            r#"1501struct Foo;1502trait Make {1503    fn new() -> Self;1504}1505impl Make for Foo {1506            //^^^1507    fn new() -> Self {1508        Self$0 {}1509    }1510}1511"#,1512        );15131514        check(1515            r#"1516struct Foo;1517trait Make {1518    fn new() -> Self;1519}1520impl Make for Foo {1521            //^^^1522    fn new() -> Self$0 {1523        Self {}1524    }1525}1526"#,1527        );1528    }15291530    #[test]1531    fn goto_def_when_used_on_definition_name_itself() {1532        check(1533            r#"1534struct Foo$0 { value: u32 }1535     //^^^1536            "#,1537        );15381539        check(1540            r#"1541struct Foo {1542    field$0: string,1543} //^^^^^1544"#,1545        );15461547        check(1548            r#"1549fn foo_test$0() { }1550 //^^^^^^^^1551"#,1552        );15531554        check(1555            r#"1556enum Foo$0 { Variant }1557   //^^^1558"#,1559        );15601561        check(1562            r#"1563enum Foo {1564    Variant1,1565    Variant2$0,1566  //^^^^^^^^1567    Variant3,1568}1569"#,1570        );15711572        check(1573            r#"1574static INNER$0: &str = "";1575     //^^^^^1576"#,1577        );15781579        check(1580            r#"1581const INNER$0: &str = "";1582    //^^^^^1583"#,1584        );15851586        check(1587            r#"1588type Thing$0 = Option<()>;1589   //^^^^^1590"#,1591        );15921593        check(1594            r#"1595trait Foo$0 { }1596    //^^^1597"#,1598        );15991600        check(1601            r#"1602trait Foo$0 = ;1603    //^^^1604"#,1605        );16061607        check(1608            r#"1609mod bar$0 { }1610  //^^^1611"#,1612        );1613    }16141615    #[test]1616    fn goto_from_macro() {1617        check(1618            r#"1619macro_rules! id {1620    ($($tt:tt)*) => { $($tt)* }1621}1622fn foo() {}1623 //^^^1624id! {1625    fn bar() {1626        fo$0o();1627    }1628}1629mod confuse_index { fn foo(); }1630"#,1631        );1632    }16331634    #[test]1635    fn goto_through_format() {1636        check(1637            r#"1638//- minicore: fmt1639#[macro_export]1640macro_rules! format {1641    ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))1642}1643pub mod __export {1644    pub use core::format_args;1645    fn foo() {} // for index confusion1646}1647fn foo() -> i8 {}1648 //^^^1649fn test() {1650    format!("{}", fo$0o())1651}1652"#,1653        );1654    }16551656    #[test]1657    fn goto_through_included_file() {1658        check(1659            r#"1660//- /main.rs1661#[rustc_builtin_macro]1662macro_rules! include {}16631664include!("foo.rs");16651666fn f() {1667    foo$0();1668}16691670mod confuse_index {1671    pub fn foo() {}1672}16731674//- /foo.rs1675fn foo() {}1676 //^^^1677        "#,1678        );1679    }16801681    #[test]1682    fn goto_through_included_file_struct_with_doc_comment() {1683        check(1684            r#"1685//- /main.rs1686#[rustc_builtin_macro]1687macro_rules! include {}16881689include!("foo.rs");16901691fn f() {1692    let x = Foo$0;1693}16941695mod confuse_index {1696    pub struct Foo;1697}16981699//- /foo.rs1700/// This is a doc comment1701pub struct Foo;1702         //^^^1703        "#,1704        );1705    }17061707    #[test]1708    fn goto_for_type_param() {1709        check(1710            r#"1711struct Foo<T: Clone> { t: $0T }1712         //^1713"#,1714        );1715    }17161717    #[test]1718    fn goto_within_macro() {1719        check(1720            r#"1721macro_rules! id {1722    ($($tt:tt)*) => ($($tt)*)1723}17241725fn foo() {1726    let x = 1;1727      //^1728    id!({1729        let y = $0x;1730        let z = y;1731    });1732}1733"#,1734        );17351736        check(1737            r#"1738macro_rules! id {1739    ($($tt:tt)*) => ($($tt)*)1740}17411742fn foo() {1743    let x = 1;1744    id!({1745        let y = x;1746          //^1747        let z = $0y;1748    });1749}1750"#,1751        );1752    }17531754    #[test]1755    fn goto_def_in_local_fn() {1756        check(1757            r#"1758fn main() {1759    fn foo() {1760        let x = 92;1761          //^1762        $0x;1763    }1764}1765"#,1766        );1767    }17681769    #[test]1770    fn goto_def_in_local_macro() {1771        check(1772            r#"1773fn bar() {1774    macro_rules! foo { () => { () } }1775               //^^^1776    $0foo!();1777}1778"#,1779        );1780    }17811782    #[test]1783    fn goto_def_for_field_init_shorthand() {1784        check(1785            r#"1786struct Foo { x: i32 }1787           //^1788fn main() {1789    let x = 92;1790      //^1791    Foo { x$0 };1792}1793"#,1794        )1795    }17961797    #[test]1798    fn goto_def_for_enum_variant_field() {1799        check(1800            r#"1801enum Foo {1802    Bar { x: i32 }1803        //^1804}1805fn baz(foo: Foo) {1806    match foo {1807        Foo::Bar { x$0 } => x1808                 //^1809    };1810}1811"#,1812        );1813    }18141815    #[test]1816    fn goto_def_for_enum_variant_self_pattern_const() {1817        check(1818            r#"1819enum Foo { Bar }1820         //^^^1821impl Foo {1822    fn baz(self) {1823        match self { Self::Bar$0 => {} }1824    }1825}1826"#,1827        );1828    }18291830    #[test]1831    fn goto_def_for_enum_variant_self_pattern_record() {1832        check(1833            r#"1834enum Foo { Bar { val: i32 } }1835         //^^^1836impl Foo {1837    fn baz(self) -> i32 {1838        match self { Self::Bar$0 { val } => {} }1839    }1840}1841"#,1842        );1843    }18441845    #[test]1846    fn goto_def_for_enum_variant_self_expr_const() {1847        check(1848            r#"1849enum Foo { Bar }1850         //^^^1851impl Foo {1852    fn baz(self) { Self::Bar$0; }1853}1854"#,1855        );1856    }18571858    #[test]1859    fn goto_def_for_enum_variant_self_expr_record() {1860        check(1861            r#"1862enum Foo { Bar { val: i32 } }1863         //^^^1864impl Foo {1865    fn baz(self) { Self::Bar$0 {val: 4}; }1866}1867"#,1868        );1869    }18701871    #[test]1872    fn goto_def_for_type_alias_generic_parameter() {1873        check(1874            r#"1875type Alias<T> = T$0;1876         //^1877"#,1878        )1879    }18801881    #[test]1882    fn goto_def_for_macro_container() {1883        check(1884            r#"1885//- /lib.rs crate:main deps:foo1886foo::module$0::mac!();18871888//- /foo/lib.rs crate:foo1889pub mod module {1890      //^^^^^^1891    #[macro_export]1892    macro_rules! _mac { () => { () } }1893    pub use crate::_mac as mac;1894}1895"#,1896        );1897    }18981899    #[test]1900    fn goto_def_for_assoc_ty_in_path() {1901        check(1902            r#"1903trait Iterator {1904    type Item;1905       //^^^^1906}19071908fn f() -> impl Iterator<Item$0 = u8> {}1909"#,1910        );1911    }19121913    #[test]1914    fn goto_def_for_super_assoc_ty_in_path() {1915        check(1916            r#"1917trait Super {1918    type Item;1919       //^^^^1920}19211922trait Sub: Super {}19231924fn f() -> impl Sub<Item$0 = u8> {}1925"#,1926        );1927    }19281929    #[test]1930    fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {1931        check(1932            r#"1933mod bar {1934    pub struct Foo {}1935             //^^^1936    pub fn Foo() {}1937}19381939fn baz() {1940    let _foo_enum: bar::Foo$0 = bar::Foo {};1941}1942        "#,1943        )1944    }19451946    #[test]1947    fn unknown_assoc_ty() {1948        check_unresolved(1949            r#"1950trait Iterator { type Item; }1951fn f() -> impl Iterator<Invalid$0 = u8> {}1952"#,1953        )1954    }19551956    #[test]1957    fn goto_def_for_assoc_ty_in_path_multiple() {1958        check(1959            r#"1960trait Iterator {1961    type A;1962       //^1963    type B;1964}19651966fn f() -> impl Iterator<A$0 = u8, B = ()> {}1967"#,1968        );1969        check(1970            r#"1971trait Iterator {1972    type A;1973    type B;1974       //^1975}19761977fn f() -> impl Iterator<A = u8, B$0 = ()> {}1978"#,1979        );1980    }19811982    #[test]1983    fn goto_def_for_assoc_ty_ufcs() {1984        check(1985            r#"1986trait Iterator {1987    type Item;1988       //^^^^1989}19901991fn g() -> <() as Iterator<Item$0 = ()>>::Item {}1992"#,1993        );1994    }19951996    #[test]1997    fn goto_def_for_assoc_ty_ufcs_multiple() {1998        check(1999            r#"2000trait Iterator {

Code quality findings 45

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
ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),
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
.unwrap()
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("no definition found")
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
.unwrap()
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("no definition found")
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
let navs = analysis.goto_definition(position, &TEST_CONFIG).unwrap();
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
&arr[0.$0.]
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
&arr[.$0.]
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
&arr[.$0.10]
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
&arr[.$0.=10]
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
Struct[0]$0;
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
foo[0]$0 = Bar;
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 _ = core::mem::offset_of!(Foo, fiel$0d);
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 _ = core::mem::offset_of!(Bar, 0.fiel$0d);
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 _ = core::mem::offset_of!(Bar, 0.Abc.0.fiel$0d);
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 _ = core::mem::offset_of!(Bar, 0.Ab$0c.0.field);
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 tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
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 (target_fn_name, expected_trait) = match fn_name_str {
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 token.kind() {
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 anc {
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
ast::Fn(fn_) => fn_.syntax().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
ast::ClosureExpr(c) => c.syntax().clone(),
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 blk.modifier() {
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
Some(ast::BlockModifier::Async(_)) => blk.syntax().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
Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),
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 focus_range = match 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 ch {
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 ch {
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 ch {
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 ch {
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 ch {
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 v {
Info: Including file content directly into the binary at compile time. Ensure this is intended, as it increases binary size and doesn't reflect runtime file changes.
info maintainability include-in-binary
let str = include_str!("foo.txt$0");
Info: Including file content directly into the binary at compile time. Ensure this is intended, as it increases binary size and doesn't reflect runtime file changes.
info maintainability include-in-binary
let str = include_str!(concat!("foo", ".tx$0t"));
Info: Including file content directly into the binary at compile time. Ensure this is intended, as it increases binary size and doesn't reflect runtime file changes.
info maintainability include-in-binary
#[doc = include_str!("docs.md$0")]
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!("{}", i);
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!("{}", i);
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 0 {
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 0 {
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 0 {
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 42 {
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 Tag(Path) {
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 x {
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 x {
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 x {

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