src/tools/rust-analyzer/crates/ide/src/goto_definition.rs RUST 4,227 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,227.
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        | COMMENT => 4,75        // index and prefix ops76        T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,77        kind if kind.is_keyword(edition) => 2,78        T!['('] | T![')'] => 2,79        kind if kind.is_trivia() => 0,80        _ => 1,81    })?;82    if let Some(doc_comment) = token_as_doc_comment(&original_token) {83        return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| {84            let nav = def.try_to_nav(sema)?;85            Some(RangeInfo::new(link_range, nav.collect()))86        });87    }8889    if let Some((range, _, _, resolution)) =90        sema.check_for_format_args_template(original_token.clone(), offset)91    {92        return Some(RangeInfo::new(93            range,94            match resolution {95                Some(res) => def_to_nav(sema, Definition::from(res)),96                None => vec![],97            },98        ));99    }100101    if let Some(navs) = handle_control_flow_keywords(sema, &original_token) {102        return Some(RangeInfo::new(original_token.text_range(), navs));103    }104105    let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);106    let mut navs = Vec::new();107    for token in tokens {108        if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {109            navs.extend(n);110            continue;111        }112113        if let Some(n) = find_definition_for_comparison_operators(sema, &token.value) {114            navs.extend(n);115            continue;116        }117118        let parent = token.value.parent()?;119120        if let Some(question_mark_conversion) = goto_question_mark_conversions(sema, &parent) {121            navs.extend(def_to_nav(sema, question_mark_conversion.into()));122            continue;123        }124125        if let Some(token) = ast::String::cast(token.value.clone())126            && let Some(original_token) = ast::String::cast(original_token.clone())127            && let Some((analysis, fixture_analysis)) =128                Analysis::from_ra_fixture(sema, original_token, &token, &config.ra_fixture)129            && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)130        {131            return hir::attach_db_allow_change(&analysis.db, || {132                goto_definition(133                    &analysis.db,134                    FilePosition { file_id: virtual_file_id, offset: file_offset },135                    config,136                )137            })138            .and_then(|navs| {139                navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()140            });141        }142143        let token_file_id = token.file_id;144        if let Some(token) = ast::String::cast(token.value.clone())145            && let Some(x) =146                try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)147        {148            navs.push(x);149            continue;150        }151152        if ast::TokenTree::can_cast(parent.kind())153            && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)154        {155            navs.push(x);156            continue;157        }158159        let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };160        navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {161            if let Definition::ExternCrateDecl(crate_def) = def {162                return crate_def163                    .resolved_crate(db)164                    .map(|it| it.root_module(db).to_nav(db))165                    .into_iter()166                    .flatten()167                    .collect();168            }169            try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))170        }));171    }172    let navs = navs.into_iter().unique().collect();173174    Some(RangeInfo::new(original_token.text_range(), navs))175}176177/// When the `?` operator is used on `Result`, go to the `From` impl if it exists as this provides more value.178fn goto_question_mark_conversions(179    sema: &Semantics<'_, RootDatabase>,180    node: &SyntaxNode,181) -> Option<hir::Function> {182    let node = ast::TryExpr::cast(node.clone())?;183    let try_expr_ty = sema.type_of_expr(&node.expr()?)?.adjusted();184185    let fd = FamousDefs(sema, try_expr_ty.krate(sema.db));186    let result_enum = fd.core_result_Result()?.into();187188    let (try_expr_ty_adt, try_expr_ty_args) = try_expr_ty.as_adt_with_args()?;189    if try_expr_ty_adt != result_enum {190        // FIXME: Support `Poll<Result>`.191        return None;192    }193    let original_err_ty = try_expr_ty_args.get(1)?.clone()?;194195    let returned_ty = sema.try_expr_returned_type(&node)?;196    let (returned_adt, returned_ty_args) = returned_ty.as_adt_with_args()?;197    if returned_adt != result_enum {198        return None;199    }200    let returned_err_ty = returned_ty_args.get(1)?.clone()?;201202    if returned_err_ty.could_unify_with_deeply(sema.db, &original_err_ty) {203        return None;204    }205206    let from_trait = fd.core_convert_From()?;207    let from_fn = from_trait.function(sema.db, sym::from)?;208    sema.resolve_trait_impl_method(209        returned_err_ty.clone(),210        from_trait,211        from_fn,212        [returned_err_ty, original_err_ty],213    )214}215216// If the token is into(), try_into(), search the definition of From, TryFrom.217fn find_definition_for_known_blanket_dual_impls(218    sema: &Semantics<'_, RootDatabase>,219    original_token: &SyntaxToken,220) -> Option<Vec<NavigationTarget>> {221    let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;222    let callable = sema.resolve_method_call_as_callable(&method_call)?;223    let CallableKind::Function(f) = callable.kind() else { return None };224    let assoc = f.as_assoc_item(sema.db)?;225226    let return_type = callable.return_type();227    let fd = FamousDefs(sema, return_type.krate(sema.db));228229    let t = match assoc.container(sema.db) {230        hir::AssocItemContainer::Trait(t) => t,231        hir::AssocItemContainer::Impl(impl_)232            if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>233        {234            let t = fd.core_convert_FromStr()?;235            let t_f = t.function(sema.db, &sym::from_str)?;236            return sema237                .resolve_trait_impl_method(238                    return_type.clone(),239                    t,240                    t_f,241                    [return_type.type_arguments().next()?],242                )243                .map(|f| def_to_nav(sema, f.into()));244        }245        hir::AssocItemContainer::Impl(_) => return None,246    };247248    let fn_name = f.name(sema.db);249    let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {250        let dual = fd.core_convert_From()?;251        let dual_f = dual.function(sema.db, &sym::from)?;252        sema.resolve_trait_impl_method(253            return_type.clone(),254            dual,255            dual_f,256            [return_type, callable.receiver_param(sema.db)?.1],257        )?258    } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {259        let dual = fd.core_convert_TryFrom()?;260        let dual_f = dual.function(sema.db, &sym::try_from)?;261        sema.resolve_trait_impl_method(262            return_type.clone(),263            dual,264            dual_f,265            // Extract the `T` from `Result<T, ..>`266            [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],267        )?268    } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {269        let dual = fd.core_fmt_Display()?;270        let dual_f = dual.function(sema.db, &sym::fmt)?;271        sema.resolve_trait_impl_method(272            return_type.clone(),273            dual,274            dual_f,275            [callable.receiver_param(sema.db)?.1.strip_reference()],276        )?277    } else {278        return None;279    };280    // Assert that we got a trait impl function, if we are back in a trait definition we didn't281    // succeed282    let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;283    let def = Definition::from(f);284    Some(def_to_nav(sema, def))285}286287// 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).288fn find_definition_for_comparison_operators(289    sema: &Semantics<'_, RootDatabase>,290    original_token: &SyntaxToken,291) -> Option<Vec<NavigationTarget>> {292    let bin_expr = ast::BinExpr::cast(original_token.parent()?)?;293294    let f = sema.resolve_bin_expr(&bin_expr)?;295    let assoc = f.as_assoc_item(sema.db)?;296297    let lhs_type = sema.type_of_expr(&bin_expr.lhs()?)?.original;298    let rhs_type = sema.type_of_expr(&bin_expr.rhs()?)?.original;299300    let t = match assoc.container(sema.db) {301        hir::AssocItemContainer::Trait(t) => t,302        hir::AssocItemContainer::Impl(_) => return None, // Already implemented by the type303    };304305    let fn_name = f.name(sema.db);306    let fn_name_str = fn_name.as_str();307308    let trait_name = t.name(sema.db);309    let trait_name_str = trait_name.as_str();310311    let (target_fn_name, expected_trait) = match fn_name_str {312        "ne" => ("eq", "PartialEq"),313        "lt" | "le" | "gt" | "ge" => ("partial_cmp", "PartialOrd"),314        _ => return None,315    };316317    if trait_name_str != expected_trait {318        return None;319    }320321    let primary_f = t.items(sema.db).into_iter().find_map(|item| {322        if let hir::AssocItem::Function(func) = item323            && func.name(sema.db).as_str() == target_fn_name324        {325            return Some(func);326        }327        None328    })?;329330    // Chalk requires ALL trait substitutions, including `Self`!331    // We must pass [Self, Rhs]332    let resolved_f = sema.resolve_trait_impl_method(333        lhs_type.clone(),334        t,335        primary_f,336        [lhs_type.clone(), rhs_type.clone()],337    )?;338339    let def = Definition::from(resolved_f);340341    Some(def_to_nav(sema, def))342}343fn try_lookup_include_path(344    sema: &Semantics<'_, RootDatabase>,345    token: InFile<ast::String>,346    file_id: FileId,347) -> Option<NavigationTarget> {348    let file = token.file_id.macro_file()?;349350    // Check that we are in the eager argument expansion of an include macro351    // that is we are the string input of it352    if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file())353        .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none())354    {355        return None;356    }357    let path = token.value.value().ok()?;358359    let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;360    let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?;361    Some(NavigationTarget {362        file_id,363        full_range: TextRange::new(0.into(), size),364        name: hir::Symbol::intern(&path),365        alias: None,366        focus_range: None,367        kind: None,368        container_name: None,369        description: None,370    })371}372373fn try_lookup_macro_def_in_macro_use(374    sema: &Semantics<'_, RootDatabase>,375    token: SyntaxToken,376) -> Option<NavigationTarget> {377    let extern_crate = token.parent()?.ancestors().find_map(ast::ExternCrate::cast)?;378    let extern_crate = sema.to_def(&extern_crate)?;379    let krate = extern_crate.resolved_crate(sema.db)?;380381    for mod_def in krate.root_module(sema.db).declarations(sema.db) {382        if let ModuleDef::Macro(mac) = mod_def383            && mac.name(sema.db).as_str() == token.text()384            && let Some(nav) = mac.try_to_nav(sema)385        {386            return Some(nav.call_site);387        }388    }389390    None391}392393/// finds the trait definition of an impl'd item, except function394/// e.g.395/// ```rust396/// trait A { type a; }397/// struct S;398/// impl A for S { type a = i32; } // <-- on this associate type, will get the location of a in the trait399/// ```400fn try_filter_trait_item_definition(401    sema: &Semantics<'_, RootDatabase>,402    def: &Definition<'_>,403) -> Option<Vec<NavigationTarget>> {404    let db = sema.db;405    let assoc = def.as_assoc_item(db)?;406    match assoc {407        AssocItem::Function(..) => None,408        AssocItem::Const(..) | AssocItem::TypeAlias(..) => {409            let trait_ = assoc.implemented_trait(db)?;410            let name = def.name(db)?;411            let discriminant_value = discriminant(&assoc);412            trait_413                .items(db)414                .iter()415                .filter(|itm| discriminant(*itm) == discriminant_value)416                .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(sema)).flatten())417                .map(|it| it.collect())418        }419    }420}421422fn handle_control_flow_keywords(423    sema: &Semantics<'_, RootDatabase>,424    token: &SyntaxToken,425) -> Option<Vec<NavigationTarget>> {426    match token.kind() {427        // For `fn` / `loop` / `while` / `for` / `async` / `match`, return the keyword it self,428        // so that VSCode will find the references when using `ctrl + click`429        T![fn] | T![async] | T![try] | T![return] => nav_for_exit_points(sema, token),430        T![loop] | T![while] | T![break] | T![continue] => nav_for_break_points(sema, token),431        T![for] if token.parent().and_then(ast::ForExpr::cast).is_some() => {432            nav_for_break_points(sema, token)433        }434        T![match] | T![=>] | T![if] => nav_for_branch_exit_points(sema, token),435        _ => None,436    }437}438439pub(crate) fn find_fn_or_blocks(440    sema: &Semantics<'_, RootDatabase>,441    token: &SyntaxToken,442) -> Vec<SyntaxNode> {443    let find_ancestors = |token: SyntaxToken| {444        let token_kind = token.kind();445446        for anc in sema.token_ancestors_with_macros(token) {447            let node = match_ast! {448                match anc {449                    ast::Fn(fn_) => fn_.syntax().clone(),450                    ast::ClosureExpr(c) => c.syntax().clone(),451                    ast::BlockExpr(blk) => {452                        match blk.modifier() {453                            Some(ast::BlockModifier::Async(_)) => blk.syntax().clone(),454                            Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => blk.syntax().clone(),455                            _ => continue,456                        }457                    },458                    _ => continue,459                }460            };461462            return Some(node);463        }464        None465    };466467    sema.descend_into_macros(token.clone()).into_iter().filter_map(find_ancestors).collect_vec()468}469470fn nav_for_exit_points(471    sema: &Semantics<'_, RootDatabase>,472    token: &SyntaxToken,473) -> Option<Vec<NavigationTarget>> {474    let db = sema.db;475    let token_kind = token.kind();476477    let navs = find_fn_or_blocks(sema, token)478        .into_iter()479        .filter_map(|node| {480            let file_id = sema.hir_file_for(&node);481482            match_ast! {483                match node {484                    ast::Fn(fn_) => {485                        let mut nav = sema.to_def(&fn_)?.try_to_nav(sema)?;486                        // For async token, we navigate to itself, which triggers487                        // VSCode to find the references488                        let focus_token = if matches!(token_kind, T![async]) {489                            fn_.async_token()?490                        } else {491                            fn_.fn_token()?492                        };493494                        let focus_frange = InFile::new(file_id, focus_token.text_range())495                            .original_node_file_range_opt(db)496                            .map(|(frange, _)| frange);497498                        if let Some(FileRange { file_id, range }) = focus_frange {499                            let contains_frange = |nav: &NavigationTarget| {500                                nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range)501                            };502503                            if let Some(def_site) = nav.def_site.as_mut() {504                                if contains_frange(def_site) {505                                    def_site.focus_range = Some(range);506                                }507                            } else if contains_frange(&nav.call_site) {508                                nav.call_site.focus_range = Some(range);509                            }510                        }511512                        Some(nav)513                    },514                    ast::ClosureExpr(c) => {515                        let pipe_tok = c.param_list().and_then(|it| it.pipe_token())?.text_range();516                        let closure_in_file = InFile::new(file_id, c.into());517                        Some(expr_to_nav(db, closure_in_file, Some(pipe_tok)))518                    },519                    ast::BlockExpr(blk) => {520                        match blk.modifier() {521                            Some(ast::BlockModifier::Async(_)) => {522                                let async_tok = blk.async_token()?.text_range();523                                let blk_in_file = InFile::new(file_id, blk.into());524                                Some(expr_to_nav(db, blk_in_file, Some(async_tok)))525                            },526                            Some(ast::BlockModifier::Try { .. }) if token_kind != T![return] => {527                                let try_tok = blk.try_block_modifier()?.try_token()?.text_range();528                                let blk_in_file = InFile::new(file_id, blk.into());529                                Some(expr_to_nav(db, blk_in_file, Some(try_tok)))530                            },531                            _ => None,532                        }533                    },534                    _ => None,535                }536            }537        })538        .flatten()539        .collect_vec();540541    Some(navs)542}543544pub(crate) fn find_branch_root(545    sema: &Semantics<'_, RootDatabase>,546    token: &SyntaxToken,547) -> Vec<SyntaxNode> {548    let find_nodes = |node_filter: fn(SyntaxNode) -> Option<SyntaxNode>| {549        sema.descend_into_macros(token.clone())550            .into_iter()551            .filter_map(|token| node_filter(token.parent()?))552            .collect_vec()553    };554555    match token.kind() {556        T![match] => find_nodes(|node| Some(ast::MatchExpr::cast(node)?.syntax().clone())),557        T![=>] => find_nodes(|node| Some(ast::MatchArm::cast(node)?.syntax().clone())),558        T![if] => find_nodes(|node| {559            let if_expr = ast::IfExpr::cast(node)?;560561            let root_if = iter::successors(Some(if_expr.clone()), |if_expr| {562                let parent_if = if_expr.syntax().parent().and_then(ast::IfExpr::cast)?;563                let ast::ElseBranch::IfExpr(else_branch) = parent_if.else_branch()? else {564                    return None;565                };566567                (else_branch.syntax() == if_expr.syntax()).then_some(parent_if)568            })569            .last()?;570571            Some(root_if.syntax().clone())572        }),573        _ => vec![],574    }575}576577fn nav_for_branch_exit_points(578    sema: &Semantics<'_, RootDatabase>,579    token: &SyntaxToken,580) -> Option<Vec<NavigationTarget>> {581    let db = sema.db;582583    let navs = match token.kind() {584        T![match] => find_branch_root(sema, token)585            .into_iter()586            .filter_map(|node| {587                let file_id = sema.hir_file_for(&node);588                let match_expr = ast::MatchExpr::cast(node)?;589                let focus_range = match_expr.match_token()?.text_range();590                let match_expr_in_file = InFile::new(file_id, match_expr.into());591                Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))592            })593            .flatten()594            .collect_vec(),595596        T![=>] => find_branch_root(sema, token)597            .into_iter()598            .filter_map(|node| {599                let match_arm = ast::MatchArm::cast(node)?;600                let match_expr = sema601                    .ancestors_with_macros(match_arm.syntax().clone())602                    .find_map(ast::MatchExpr::cast)?;603                let file_id = sema.hir_file_for(match_expr.syntax());604                let focus_range = match_arm.fat_arrow_token()?.text_range();605                let match_expr_in_file = InFile::new(file_id, match_expr.into());606                Some(expr_to_nav(db, match_expr_in_file, Some(focus_range)))607            })608            .flatten()609            .collect_vec(),610611        T![if] => find_branch_root(sema, token)612            .into_iter()613            .filter_map(|node| {614                let file_id = sema.hir_file_for(&node);615                let if_expr = ast::IfExpr::cast(node)?;616                let focus_range = if_expr.if_token()?.text_range();617                let if_expr_in_file = InFile::new(file_id, if_expr.into());618                Some(expr_to_nav(db, if_expr_in_file, Some(focus_range)))619            })620            .flatten()621            .collect_vec(),622623        _ => return Some(Vec::new()),624    };625626    Some(navs)627}628629fn nav_for_break_points(630    sema: &Semantics<'_, RootDatabase>,631    token: &SyntaxToken,632) -> Option<Vec<NavigationTarget>> {633    let db = sema.db;634635    let navs = find_loops(sema, token)?636        .filter_map(|expr| {637            let file_id = sema.hir_file_for(expr.syntax());638            let expr_in_file = InFile::new(file_id, expr.clone());639            let focus_range = match expr {640                ast::Expr::LoopExpr(loop_) => loop_.loop_token()?.text_range(),641                ast::Expr::WhileExpr(while_) => while_.while_token()?.text_range(),642                ast::Expr::ForExpr(for_) => for_.for_token()?.text_range(),643                // We guarantee that the label exists644                ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(),645                _ => return None,646            };647            let nav = expr_to_nav(db, expr_in_file, Some(focus_range));648            Some(nav)649        })650        .flatten()651        .collect_vec();652653    Some(navs)654}655656fn def_to_nav(sema: &Semantics<'_, RootDatabase>, def: Definition<'_>) -> Vec<NavigationTarget> {657    def.try_to_nav(sema).map(|it| it.collect()).unwrap_or_default()658}659660fn expr_to_nav(661    db: &RootDatabase,662    InFile { file_id, value }: InFile<ast::Expr>,663    focus_range: Option<TextRange>,664) -> UpmappingResult<NavigationTarget> {665    let kind = SymbolKind::Label;666667    let value_range = value.syntax().text_range();668    let navs = navigation_target::orig_range_with_focus_r(db, file_id, value_range, focus_range);669    navs.map(|(hir::FileRangeWrapper { file_id, range }, focus_range)| {670        NavigationTarget::from_syntax(671            file_id,672            hir::Symbol::intern("<expr>"),673            focus_range,674            range,675            kind,676        )677    })678}679680#[cfg(test)]681mod tests {682    use crate::{GotoDefinitionConfig, fixture};683    use ide_db::{FileRange, ra_fixture::RaFixtureConfig};684    use itertools::Itertools;685686    const TEST_CONFIG: GotoDefinitionConfig<'_> =687        GotoDefinitionConfig { ra_fixture: RaFixtureConfig::default() };688689    #[track_caller]690    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {691        let (analysis, position, expected) = fixture::annotations(ra_fixture);692        let navs = analysis693            .goto_definition(position, &TEST_CONFIG)694            .unwrap()695            .expect("no definition found")696            .info;697698        let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());699        let navs = navs700            .into_iter()701            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })702            .sorted_by_key(cmp)703            .collect::<Vec<_>>();704        let expected = expected705            .into_iter()706            .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range })707            .sorted_by_key(cmp)708            .collect::<Vec<_>>();709710        assert_eq!(expected, navs);711    }712713    fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {714        let (analysis, position) = fixture::position(ra_fixture);715        let navs = analysis716            .goto_definition(position, &TEST_CONFIG)717            .unwrap()718            .expect("no definition found")719            .info;720721        assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")722    }723724    fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {725        let (analysis, position, _) = fixture::annotations(ra_fixture);726        let navs = analysis727            .goto_definition(position, &TEST_CONFIG)728            .unwrap()729            .expect("no definition found")730            .info;731        assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());732        let Some(target) = navs.into_iter().next() else {733            panic!("expected single navigation target but encountered none");734        };735        assert_eq!(target.name, hir::Symbol::intern(expected_name));736    }737738    #[test]739    fn goto_def_pat_range_to_inclusive() {740        check_name(741            "RangeToInclusive",742            r#"743//- minicore: range744fn f(ch: char) -> bool {745    match ch {746        ..$0='z' => true,747        _ => false748    }749}750"#,751        );752    }753754    #[test]755    fn goto_def_pat_range_to() {756        check_name(757            "RangeTo",758            r#"759//- minicore: range760fn f(ch: char) -> bool {761    match ch {762        .$0.'z' => true,763        _ => false764    }765}766"#,767        );768    }769770    #[test]771    fn goto_def_pat_range() {772        check_name(773            "Range",774            r#"775//- minicore: range776fn f(ch: char) -> bool {777    match ch {778        'a'.$0.'z' => true,779        _ => false780    }781}782"#,783        );784    }785786    #[test]787    fn goto_def_pat_range_inclusive() {788        check_name(789            "RangeInclusive",790            r#"791//- minicore: range792fn f(ch: char) -> bool {793    match ch {794        'a'..$0='z' => true,795        _ => false796    }797}798"#,799        );800    }801802    #[test]803    fn goto_def_pat_range_from() {804        check_name(805            "RangeFrom",806            r#"807//- minicore: range808fn f(ch: char) -> bool {809    match ch {810        'a'..$0 => true,811        _ => false812    }813}814"#,815        );816    }817818    #[test]819    fn goto_def_expr_range() {820        check_name(821            "Range",822            r#"823//- minicore: range824let x = 0.$0.1;825"#,826        );827    }828829    #[test]830    fn goto_def_expr_range_from() {831        check_name(832            "RangeFrom",833            r#"834//- minicore: range835fn f(arr: &[i32]) -> &[i32] {836    &arr[0.$0.]837}838"#,839        );840    }841842    #[test]843    fn goto_def_expr_range_inclusive() {844        check_name(845            "RangeInclusive",846            r#"847//- minicore: range848let x = 0.$0.=1;849"#,850        );851    }852853    #[test]854    fn goto_def_expr_range_full() {855        check_name(856            "RangeFull",857            r#"858//- minicore: range859fn f(arr: &[i32]) -> &[i32] {860    &arr[.$0.]861}862"#,863        );864    }865866    #[test]867    fn goto_def_expr_range_to() {868        check_name(869            "RangeTo",870            r#"871//- minicore: range872fn f(arr: &[i32]) -> &[i32] {873    &arr[.$0.10]874}875"#,876        );877    }878879    #[test]880    fn goto_def_expr_range_to_inclusive() {881        check_name(882            "RangeToInclusive",883            r#"884//- minicore: range885fn f(arr: &[i32]) -> &[i32] {886    &arr[.$0.=10]887}888"#,889        );890    }891892    #[test]893    fn goto_def_in_included_file() {894        check(895            r#"896//- minicore:include897//- /main.rs898899include!("a.rs");900901fn main() {902    foo();903}904905//- /a.rs906fn func_in_include() {907 //^^^^^^^^^^^^^^^908}909910fn foo() {911    func_in_include$0();912}913"#,914        );915    }916917    #[test]918    fn goto_def_in_included_file_nested() {919        check(920            r#"921//- minicore:include922//- /main.rs923924macro_rules! passthrough {925    ($($tt:tt)*) => { $($tt)* }926}927928passthrough!(include!("a.rs"));929930fn main() {931    foo();932}933934//- /a.rs935fn func_in_include() {936 //^^^^^^^^^^^^^^^937}938939fn foo() {940    func_in_include$0();941}942"#,943        );944    }945946    #[test]947    fn goto_def_in_included_file_inside_mod() {948        check(949            r#"950//- minicore:include951//- /main.rs952mod a {953    include!("b.rs");954}955//- /b.rs956fn func_in_include() {957 //^^^^^^^^^^^^^^^958}959fn foo() {960    func_in_include$0();961}962"#,963        );964965        check(966            r#"967//- minicore:include968//- /main.rs969mod a {970    include!("a.rs");971}972//- /a.rs973fn func_in_include() {974 //^^^^^^^^^^^^^^^975}976977fn foo() {978    func_in_include$0();979}980"#,981        );982    }983984    #[test]985    fn goto_def_if_items_same_name() {986        check(987            r#"988trait Trait {989    type A;990    const A: i32;991        //^992}993994struct T;995impl Trait for T {996    type A = i32;997    const A$0: i32 = -9;998}"#,999        );1000    }10011002    #[test]1003    fn goto_def_array_length_prefers_value_namespace() {1004        check(1005            r#"1006struct N;10071008trait Trait {}10091010impl<const N: usize> Trait for [N; N$0] {}1011         //^1012"#,1013        );1014    }10151016    #[test]1017    fn goto_def_in_mac_call_in_attr_invoc() {1018        check(1019            r#"1020//- proc_macros: identity1021pub struct Struct {1022        // ^^^^^^1023    field: i32,1024}10251026macro_rules! identity {1027    ($($tt:tt)*) => {$($tt)*};1028}10291030#[proc_macros::identity]1031fn function() {1032    identity!(Struct$0 { field: 0 });1033}10341035"#,1036        )1037    }10381039    #[test]1040    fn goto_def_for_extern_crate() {1041        check(1042            r#"1043//- /main.rs crate:main deps:std1044extern crate std$0;1045//- /std/lib.rs crate:std1046// empty1047//^file1048"#,1049        )1050    }10511052    #[test]1053    fn goto_def_for_renamed_extern_crate() {1054        check(1055            r#"1056//- /main.rs crate:main deps:std1057extern crate std as abc$0;1058//- /std/lib.rs crate:std1059// empty1060//^file1061"#,1062        )1063    }10641065    #[test]1066    fn goto_def_in_items() {1067        check(1068            r#"1069struct Foo;1070     //^^^1071enum E { X(Foo$0) }1072"#,1073        );1074    }10751076    #[test]1077    fn goto_def_at_start_of_item() {1078        check(1079            r#"1080struct Foo;1081     //^^^1082enum E { X($0Foo) }1083"#,1084        );1085    }10861087    #[test]1088    fn goto_definition_resolves_correct_name() {1089        check(1090            r#"1091//- /lib.rs1092use a::Foo;1093mod a;1094mod b;1095enum E { X(Foo$0) }10961097//- /a.rs1098pub struct Foo;1099         //^^^1100//- /b.rs1101pub struct Foo;1102"#,1103        );1104    }11051106    #[test]1107    fn goto_def_for_module_declaration() {1108        check(1109            r#"1110//- /lib.rs1111mod $0foo;11121113//- /foo.rs1114// empty1115//^file1116"#,1117        );11181119        check(1120            r#"1121//- /lib.rs1122mod $0foo;11231124//- /foo/mod.rs1125// empty1126//^file1127"#,1128        );1129    }11301131    #[test]1132    fn goto_def_for_macros() {1133        check(1134            r#"1135macro_rules! foo { () => { () } }1136           //^^^1137fn bar() {1138    $0foo!();1139}1140"#,1141        );1142    }11431144    #[test]1145    fn goto_def_for_macros_from_other_crates() {1146        check(1147            r#"1148//- /lib.rs crate:main deps:foo1149use foo::foo;1150fn bar() {1151    $0foo!();1152}11531154//- /foo/lib.rs crate:foo1155#[macro_export]1156macro_rules! foo { () => { () } }1157           //^^^1158"#,1159        );1160    }11611162    #[test]1163    fn goto_def_for_macros_in_use_tree() {1164        check(1165            r#"1166//- /lib.rs crate:main deps:foo1167use foo::foo$0;11681169//- /foo/lib.rs crate:foo1170#[macro_export]1171macro_rules! foo { () => { () } }1172           //^^^1173"#,1174        );1175    }11761177    #[test]1178    fn goto_def_for_macro_defined_fn_with_arg() {1179        check(1180            r#"1181//- /lib.rs1182macro_rules! define_fn {1183    ($name:ident) => (fn $name() {})1184}11851186define_fn!(foo);1187         //^^^11881189fn bar() {1190   $0foo();1191}1192"#,1193        );1194    }11951196    #[test]1197    fn goto_def_for_macro_defined_fn_no_arg() {1198        check(1199            r#"1200//- /lib.rs1201macro_rules! define_fn {1202    () => (fn foo() {})1203            //^^^1204}12051206  define_fn!();1207//^^^^^^^^^^1208fn bar() {1209   $0foo();1210}1211"#,1212        );1213    }12141215    #[test]1216    fn goto_definition_works_for_macro_inside_pattern() {1217        check(1218            r#"1219//- /lib.rs1220macro_rules! foo {() => {0}}1221           //^^^12221223fn bar() {1224    match (0,1) {1225        ($0foo!(), _) => {}1226    }1227}1228"#,1229        );1230    }12311232    #[test]1233    fn goto_definition_works_for_macro_inside_match_arm_lhs() {1234        check(1235            r#"1236//- /lib.rs1237macro_rules! foo {() => {0}}1238           //^^^1239fn bar() {1240    match 0 {1241        $0foo!() => {}1242    }1243}1244"#,1245        );1246    }12471248    #[test]1249    fn goto_definition_works_for_consts_inside_range_pattern() {1250        check(1251            r#"1252//- /lib.rs1253const A: u32 = 0;1254    //^12551256fn bar(v: u32) {1257    match v {1258        0..=$0A => {}1259        _ => {}1260    }1261}1262"#,1263        );1264    }12651266    #[test]1267    fn goto_def_for_use_alias() {1268        check(1269            r#"1270//- /lib.rs crate:main deps:foo1271use foo as bar$0;12721273//- /foo/lib.rs crate:foo1274// empty1275//^file1276"#,1277        );1278    }12791280    #[test]1281    fn goto_def_for_use_alias_foo_macro() {1282        check(1283            r#"1284//- /lib.rs crate:main deps:foo1285use foo::foo as bar$0;12861287//- /foo/lib.rs crate:foo1288#[macro_export]1289macro_rules! foo { () => { () } }1290           //^^^1291"#,1292        );1293    }12941295    #[test]1296    fn goto_def_for_methods() {1297        check(1298            r#"1299struct Foo;1300impl Foo {1301    fn frobnicate(&self) { }1302     //^^^^^^^^^^1303}13041305fn bar(foo: &Foo) {1306    foo.frobnicate$0();1307}1308"#,1309        );1310    }13111312    #[test]1313    fn goto_def_for_fields() {1314        check(1315            r#"1316struct Foo {1317    spam: u32,1318} //^^^^13191320fn bar(foo: &Foo) {1321    foo.spam$0;1322}1323"#,1324        );1325    }13261327    #[test]1328    fn goto_def_for_record_fields() {1329        check(1330            r#"1331//- /lib.rs1332struct Foo {1333    spam: u32,1334} //^^^^13351336fn bar() -> Foo {1337    Foo {1338        spam$0: 0,1339    }1340}1341"#,1342        );1343    }13441345    #[test]1346    fn goto_def_for_record_pat_fields() {1347        check(1348            r#"1349//- /lib.rs1350struct Foo {1351    spam: u32,1352} //^^^^13531354fn bar(foo: Foo) -> Foo {1355    let Foo { spam$0: _, } = foo1356}1357"#,1358        );1359    }13601361    #[test]1362    fn goto_def_for_record_fields_macros() {1363        check(1364            r"1365macro_rules! m { () => { 92 };}1366struct Foo { spam: u32 }1367           //^^^^13681369fn bar() -> Foo {1370    Foo { spam$0: m!() }1371}1372",1373        );1374    }13751376    #[test]1377    fn goto_for_tuple_fields() {1378        check(1379            r#"1380struct Foo(u32);1381         //^^^13821383fn bar() {1384    let foo = Foo(0);1385    foo.$00;1386}1387"#,1388        );1389    }13901391    #[test]1392    fn goto_def_for_ufcs_inherent_methods() {1393        check(1394            r#"1395struct Foo;1396impl Foo {1397    fn frobnicate() { }1398}    //^^^^^^^^^^13991400fn bar(foo: &Foo) {1401    Foo::frobnicate$0();1402}1403"#,1404        );1405    }14061407    #[test]1408    fn goto_def_for_ufcs_trait_methods_through_traits() {1409        check(1410            r#"1411trait Foo {1412    fn frobnicate();1413}    //^^^^^^^^^^14141415fn bar() {1416    Foo::frobnicate$0();1417}1418"#,1419        );1420    }14211422    #[test]1423    fn goto_def_for_ufcs_trait_methods_through_self() {1424        check(1425            r#"1426struct Foo;1427trait Trait {1428    fn frobnicate();1429}    //^^^^^^^^^^1430impl Trait for Foo {}14311432fn bar() {1433    Foo::frobnicate$0();1434}1435"#,1436        );1437    }14381439    #[test]1440    fn goto_definition_on_self() {1441        check(1442            r#"1443struct Foo;1444impl Foo {1445   //^^^1446    pub fn new() -> Self {1447        Self$0 {}1448    }1449}1450"#,1451        );1452        check(1453            r#"1454struct Foo;1455impl Foo {1456   //^^^1457    pub fn new() -> Self$0 {1458        Self {}1459    }1460}1461"#,1462        );14631464        check(1465            r#"1466enum Foo { A }1467impl Foo {1468   //^^^1469    pub fn new() -> Self$0 {1470        Foo::A1471    }1472}1473"#,1474        );14751476        check(1477            r#"1478enum Foo { A }1479impl Foo {1480   //^^^1481    pub fn thing(a: &Self$0) {1482    }1483}1484"#,1485        );1486    }14871488    #[test]1489    fn goto_definition_on_self_in_trait_impl() {1490        check(1491            r#"1492struct Foo;1493trait Make {1494    fn new() -> Self;1495}1496impl Make for Foo {1497            //^^^1498    fn new() -> Self {1499        Self$0 {}1500    }1501}1502"#,1503        );15041505        check(1506            r#"1507struct Foo;1508trait Make {1509    fn new() -> Self;1510}1511impl Make for Foo {1512            //^^^1513    fn new() -> Self$0 {1514        Self {}1515    }1516}1517"#,1518        );1519    }15201521    #[test]1522    fn goto_def_when_used_on_definition_name_itself() {1523        check(1524            r#"1525struct Foo$0 { value: u32 }1526     //^^^1527            "#,1528        );15291530        check(1531            r#"1532struct Foo {1533    field$0: string,1534} //^^^^^1535"#,1536        );15371538        check(1539            r#"1540fn foo_test$0() { }1541 //^^^^^^^^1542"#,1543        );15441545        check(1546            r#"1547enum Foo$0 { Variant }1548   //^^^1549"#,1550        );15511552        check(1553            r#"1554enum Foo {1555    Variant1,1556    Variant2$0,1557  //^^^^^^^^1558    Variant3,1559}1560"#,1561        );15621563        check(1564            r#"1565static INNER$0: &str = "";1566     //^^^^^1567"#,1568        );15691570        check(1571            r#"1572const INNER$0: &str = "";1573    //^^^^^1574"#,1575        );15761577        check(1578            r#"1579type Thing$0 = Option<()>;1580   //^^^^^1581"#,1582        );15831584        check(1585            r#"1586trait Foo$0 { }1587    //^^^1588"#,1589        );15901591        check(1592            r#"1593trait Foo$0 = ;1594    //^^^1595"#,1596        );15971598        check(1599            r#"1600mod bar$0 { }1601  //^^^1602"#,1603        );1604    }16051606    #[test]1607    fn goto_from_macro() {1608        check(1609            r#"1610macro_rules! id {1611    ($($tt:tt)*) => { $($tt)* }1612}1613fn foo() {}1614 //^^^1615id! {1616    fn bar() {1617        fo$0o();1618    }1619}1620mod confuse_index { fn foo(); }1621"#,1622        );1623    }16241625    #[test]1626    fn goto_through_format() {1627        check(1628            r#"1629//- minicore: fmt1630#[macro_export]1631macro_rules! format {1632    ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))1633}1634pub mod __export {1635    pub use core::format_args;1636    fn foo() {} // for index confusion1637}1638fn foo() -> i8 {}1639 //^^^1640fn test() {1641    format!("{}", fo$0o())1642}1643"#,1644        );1645    }16461647    #[test]1648    fn goto_through_included_file() {1649        check(1650            r#"1651//- /main.rs1652#[rustc_builtin_macro]1653macro_rules! include {}16541655include!("foo.rs");16561657fn f() {1658    foo$0();1659}16601661mod confuse_index {1662    pub fn foo() {}1663}16641665//- /foo.rs1666fn foo() {}1667 //^^^1668        "#,1669        );1670    }16711672    #[test]1673    fn goto_through_included_file_struct_with_doc_comment() {1674        check(1675            r#"1676//- /main.rs1677#[rustc_builtin_macro]1678macro_rules! include {}16791680include!("foo.rs");16811682fn f() {1683    let x = Foo$0;1684}16851686mod confuse_index {1687    pub struct Foo;1688}16891690//- /foo.rs1691/// This is a doc comment1692pub struct Foo;1693         //^^^1694        "#,1695        );1696    }16971698    #[test]1699    fn goto_for_type_param() {1700        check(1701            r#"1702struct Foo<T: Clone> { t: $0T }1703         //^1704"#,1705        );1706    }17071708    #[test]1709    fn goto_within_macro() {1710        check(1711            r#"1712macro_rules! id {1713    ($($tt:tt)*) => ($($tt)*)1714}17151716fn foo() {1717    let x = 1;1718      //^1719    id!({1720        let y = $0x;1721        let z = y;1722    });1723}1724"#,1725        );17261727        check(1728            r#"1729macro_rules! id {1730    ($($tt:tt)*) => ($($tt)*)1731}17321733fn foo() {1734    let x = 1;1735    id!({1736        let y = x;1737          //^1738        let z = $0y;1739    });1740}1741"#,1742        );1743    }17441745    #[test]1746    fn goto_def_in_local_fn() {1747        check(1748            r#"1749fn main() {1750    fn foo() {1751        let x = 92;1752          //^1753        $0x;1754    }1755}1756"#,1757        );1758    }17591760    #[test]1761    fn goto_def_in_local_macro() {1762        check(1763            r#"1764fn bar() {1765    macro_rules! foo { () => { () } }1766               //^^^1767    $0foo!();1768}1769"#,1770        );1771    }17721773    #[test]1774    fn goto_def_for_field_init_shorthand() {1775        check(1776            r#"1777struct Foo { x: i32 }1778           //^1779fn main() {1780    let x = 92;1781      //^1782    Foo { x$0 };1783}1784"#,1785        )1786    }17871788    #[test]1789    fn goto_def_for_enum_variant_field() {1790        check(1791            r#"1792enum Foo {1793    Bar { x: i32 }1794        //^1795}1796fn baz(foo: Foo) {1797    match foo {1798        Foo::Bar { x$0 } => x1799                 //^1800    };1801}1802"#,1803        );1804    }18051806    #[test]1807    fn goto_def_for_enum_variant_self_pattern_const() {1808        check(1809            r#"1810enum Foo { Bar }1811         //^^^1812impl Foo {1813    fn baz(self) {1814        match self { Self::Bar$0 => {} }1815    }1816}1817"#,1818        );1819    }18201821    #[test]1822    fn goto_def_for_enum_variant_self_pattern_record() {1823        check(1824            r#"1825enum Foo { Bar { val: i32 } }1826         //^^^1827impl Foo {1828    fn baz(self) -> i32 {1829        match self { Self::Bar$0 { val } => {} }1830    }1831}1832"#,1833        );1834    }18351836    #[test]1837    fn goto_def_for_enum_variant_self_expr_const() {1838        check(1839            r#"1840enum Foo { Bar }1841         //^^^1842impl Foo {1843    fn baz(self) { Self::Bar$0; }1844}1845"#,1846        );1847    }18481849    #[test]1850    fn goto_def_for_enum_variant_self_expr_record() {1851        check(1852            r#"1853enum Foo { Bar { val: i32 } }1854         //^^^1855impl Foo {1856    fn baz(self) { Self::Bar$0 {val: 4}; }1857}1858"#,1859        );1860    }18611862    #[test]1863    fn goto_def_for_type_alias_generic_parameter() {1864        check(1865            r#"1866type Alias<T> = T$0;1867         //^1868"#,1869        )1870    }18711872    #[test]1873    fn goto_def_for_macro_container() {1874        check(1875            r#"1876//- /lib.rs crate:main deps:foo1877foo::module$0::mac!();18781879//- /foo/lib.rs crate:foo1880pub mod module {1881      //^^^^^^1882    #[macro_export]1883    macro_rules! _mac { () => { () } }1884    pub use crate::_mac as mac;1885}1886"#,1887        );1888    }18891890    #[test]1891    fn goto_def_for_assoc_ty_in_path() {1892        check(1893            r#"1894trait Iterator {1895    type Item;1896       //^^^^1897}18981899fn f() -> impl Iterator<Item$0 = u8> {}1900"#,1901        );1902    }19031904    #[test]1905    fn goto_def_for_super_assoc_ty_in_path() {1906        check(1907            r#"1908trait Super {1909    type Item;1910       //^^^^1911}19121913trait Sub: Super {}19141915fn f() -> impl Sub<Item$0 = u8> {}1916"#,1917        );1918    }19191920    #[test]1921    fn goto_def_for_module_declaration_in_path_if_types_and_values_same_name() {1922        check(1923            r#"1924mod bar {1925    pub struct Foo {}1926             //^^^1927    pub fn Foo() {}1928}19291930fn baz() {1931    let _foo_enum: bar::Foo$0 = bar::Foo {};1932}1933        "#,1934        )1935    }19361937    #[test]1938    fn unknown_assoc_ty() {1939        check_unresolved(1940            r#"1941trait Iterator { type Item; }1942fn f() -> impl Iterator<Invalid$0 = u8> {}1943"#,1944        )1945    }19461947    #[test]1948    fn goto_def_for_assoc_ty_in_path_multiple() {1949        check(1950            r#"1951trait Iterator {1952    type A;1953       //^1954    type B;1955}19561957fn f() -> impl Iterator<A$0 = u8, B = ()> {}1958"#,1959        );1960        check(1961            r#"1962trait Iterator {1963    type A;1964    type B;1965       //^1966}19671968fn f() -> impl Iterator<A = u8, B$0 = ()> {}1969"#,1970        );1971    }19721973    #[test]1974    fn goto_def_for_assoc_ty_ufcs() {1975        check(1976            r#"1977trait Iterator {1978    type Item;1979       //^^^^1980}19811982fn g() -> <() as Iterator<Item$0 = ()>>::Item {}1983"#,1984        );1985    }19861987    #[test]1988    fn goto_def_for_assoc_ty_ufcs_multiple() {1989        check(1990            r#"1991trait Iterator {1992    type A;1993       //^1994    type B;1995}19961997fn g() -> <() as Iterator<A$0 = (), B = u8>>::B {}1998"#,1999        );2000        check(

Code quality findings 50

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
// We must pass [Self, Rhs]
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: 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
impl<const N: usize> Trait for [N; N$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
/// Blah, [`bar`](bar) .. [`foo`](foo$0) has [`bar`](bar)
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
/// You might want to see [`std::fs::read()`] too.
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
/// Gives you a [`TheItem$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
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: This standard library function returns a Result. Ensure the Result is handled properly (e.g., using '?', match, if let) rather than potentially panicking with .unwrap() or .expect().
info correctness unhandled-result
/// You might want to see [`std::fs::read()`] too.
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.