src/tools/rust-analyzer/crates/ide-completion/src/render.rs RUST 4,936 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,936.
1//! `render` module provides utilities for rendering completion suggestions2//! into code pieces that will be presented to user.34pub(crate) mod const_;5pub(crate) mod function;6pub(crate) mod literal;7pub(crate) mod macro_;8pub(crate) mod pattern;9pub(crate) mod type_alias;10pub(crate) mod union_literal;11pub(crate) mod variant;1213use hir::{AsAssocItem, HasAttrs, HirDisplay, Impl, ModuleDef, ScopeDef, Type};14use ide_db::text_edit::TextEdit;15use ide_db::{16    RootDatabase, SnippetCap, SymbolKind,17    documentation::{Documentation, HasDocs},18    helpers::item_name,19    imports::import_assets::LocatedImport,20};21use syntax::{AstNode, SmolStr, SyntaxKind, TextRange, ToSmolStr, ast, format_smolstr};2223use crate::{24    CompletionContext, CompletionItem, CompletionItemKind, CompletionItemRefMode,25    CompletionRelevance,26    context::{27        DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext, TypeLocation,28    },29    item::{Builder, CompletionRelevanceTypeMatch},30    render::{31        function::render_fn,32        literal::render_variant_lit,33        macro_::{render_macro, render_macro_pat},34    },35};36/// Interface for data and methods required for items rendering.37#[derive(Debug, Clone)]38pub(crate) struct RenderContext<'a, 'db> {39    completion: &'a CompletionContext<'a, 'db>,40    is_private_editable: bool,41    import_to_add: Option<LocatedImport>,42    doc_aliases: Vec<SmolStr>,43}4445impl<'a, 'db> RenderContext<'a, 'db> {46    pub(crate) fn new(completion: &'a CompletionContext<'a, 'db>) -> RenderContext<'a, 'db> {47        RenderContext {48            completion,49            is_private_editable: false,50            import_to_add: None,51            doc_aliases: vec![],52        }53    }5455    pub(crate) fn private_editable(mut self, private_editable: bool) -> Self {56        self.is_private_editable = private_editable;57        self58    }5960    pub(crate) fn import_to_add(mut self, import_to_add: Option<LocatedImport>) -> Self {61        self.import_to_add = import_to_add;62        self63    }6465    pub(crate) fn doc_aliases(mut self, doc_aliases: Vec<SmolStr>) -> Self {66        self.doc_aliases = doc_aliases;67        self68    }6970    fn snippet_cap(&self) -> Option<SnippetCap> {71        self.completion.config.snippet_cap72    }7374    fn db(&self) -> &'db RootDatabase {75        self.completion.db76    }7778    fn source_range(&self) -> TextRange {79        self.completion.source_range()80    }8182    fn completion_relevance(&self) -> CompletionRelevance {83        CompletionRelevance {84            is_private_editable: self.is_private_editable,85            requires_import: self.import_to_add.is_some(),86            ..Default::default()87        }88    }8990    fn is_immediately_after_macro_bang(&self) -> bool {91        self.completion.token.kind() == SyntaxKind::BANG92            && self.completion.token.parent().is_some_and(|it| it.kind() == SyntaxKind::MACRO_CALL)93    }9495    /// Whether `def` is deprecated.96    ///97    /// This can happen for two reasons:98    /// - the def is marked with `#[deprecated]`99    /// - the def is an assoc item whose trait is deprecated100    ///101    /// In order to be able to check for the latter, we'd ideally want to `try_as_dyn<_, dyn AsAssocItem>(def)`102    /// (see [`try_as_dyn`][]), but that function is currently unstable. Therefore, we employ a hack instead:103    /// if `def` can be an assoc item, it should be passed to this method as follows:104    /// ```ignore105    /// self.is_deprecated(def, Some(def))106    /// ```107    /// otherwise, it should be passed as:108    /// ```ignore109    /// self.is_deprecated(def, None)110    /// ```111    ///112    /// [`try_as_dyn`]: https://doc.rust-lang.org/std/any/fn.try_as_dyn.html113    fn is_deprecated(&self, def: impl HasAttrs, def_as_assoc_item: Option<hir::AssocItem>) -> bool {114        let db = self.db();115        def.attrs(db).is_deprecated()116            || def_as_assoc_item117                .and_then(|assoc| assoc.container_or_implemented_trait(db))118                .is_some_and(|trait_| {119                    self.is_deprecated(trait_, None /* traits can't be assoc items */)120                })121    }122123    /// Whether an enum variant should be rendered as deprecated.124    ///125    /// A variant inherits deprecation from its parent enum, matching rustc's126    /// behavior where `#[deprecated]` on an enum applies to its variants.127    fn is_variant_deprecated(&self, variant: hir::EnumVariant) -> bool {128        let db = self.db();129        variant.attrs(db).is_deprecated() || variant.parent_enum(db).attrs(db).is_deprecated()130    }131132    // FIXME: remove this133    fn docs(&self, def: impl HasDocs) -> Option<Documentation<'a>> {134        def.docs(self.db())135    }136}137138pub(crate) fn render_field(139    ctx: RenderContext<'_, '_>,140    dot_access: &DotAccess<'_>,141    receiver: Option<SmolStr>,142    field: hir::Field,143    ty: &hir::Type<'_>,144) -> CompletionItem {145    let db = ctx.db();146    let is_deprecated = ctx.is_deprecated(field, None /* fields can't be assoc items */);147    let name = field.name(db);148    let (name, escaped_name) =149        (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr());150    let mut item = CompletionItem::new(151        SymbolKind::Field,152        ctx.source_range(),153        field_with_receiver(receiver.as_deref(), &name),154        ctx.completion.edition,155    );156    item.set_relevance(CompletionRelevance {157        type_match: compute_type_match(ctx.completion, ty),158        exact_name_match: compute_exact_name_match(ctx.completion, &name),159        is_skipping_completion: receiver.is_some(),160        ..CompletionRelevance::default()161    });162    item.detail(ty.display(db, ctx.completion.display_target).to_string())163        .set_documentation(field.docs(db))164        .set_deprecated(is_deprecated)165        .lookup_by(name);166167    let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. });168    if !is_field_access || ty.is_fn() || ty.is_closure() {169        let mut builder = TextEdit::builder();170        // Using TextEdit, insert '(' before the struct name and ')' before the171        // dot access, then comes the field name and optionally insert function172        // call parens.173174        builder.replace(175            ctx.source_range(),176            field_with_receiver(receiver.as_deref(), &escaped_name).into(),177        );178179        let expected_fn_type =180            ctx.completion.expected_type.as_ref().is_some_and(|ty| ty.is_fn() || ty.is_closure());181182        if !expected_fn_type183            && let Some(receiver) = &dot_access.receiver184            && let Some(receiver) = ctx.completion.sema.original_range_opt(receiver.syntax())185        {186            builder.insert(receiver.range.start(), "(".to_owned());187            builder.insert(ctx.source_range().end(), ")".to_owned());188189            let is_parens_needed = !matches!(dot_access.kind, DotAccessKind::Method);190191            if is_parens_needed {192                builder.insert(ctx.source_range().end(), "()".to_owned());193            }194        }195196        item.text_edit(builder.finish());197    } else {198        item.insert_text(field_with_receiver(receiver.as_deref(), &escaped_name));199    }200    if let Some(receiver) = &dot_access.receiver201        && let Some(original) = ctx.completion.sema.original_range_opt(receiver.syntax())202        && let Some(ref_mode) = compute_ref_match(ctx.completion, ty)203    {204        item.ref_match(ref_mode, original.range.start());205    }206    item.doc_aliases(ctx.doc_aliases);207    item.build(db)208}209210fn field_with_receiver(receiver: Option<&str>, field_name: &str) -> SmolStr {211    receiver212        .map_or_else(|| field_name.into(), |receiver| format_smolstr!("{}.{field_name}", receiver))213}214215pub(crate) fn render_tuple_field(216    ctx: RenderContext<'_, '_>,217    receiver: Option<SmolStr>,218    field: usize,219    ty: &hir::Type<'_>,220) -> CompletionItem {221    let mut item = CompletionItem::new(222        SymbolKind::Field,223        ctx.source_range(),224        field_with_receiver(receiver.as_deref(), &field.to_string()),225        ctx.completion.edition,226    );227    item.detail(ty.display(ctx.db(), ctx.completion.display_target).to_string())228        .lookup_by(field.to_string());229    item.set_relevance(CompletionRelevance {230        is_skipping_completion: receiver.is_some(),231        ..ctx.completion_relevance()232    });233    item.build(ctx.db())234}235236pub(crate) fn render_type_inference(237    ty_string: String,238    ctx: &CompletionContext<'_, '_>,239    path_ctx: &PathCompletionCtx<'_>,240) -> CompletionItem {241    let mut builder = CompletionItem::new(242        CompletionItemKind::InferredType,243        ctx.source_range(),244        &ty_string,245        ctx.edition,246    );247    adds_ret_type_arrow(ctx, path_ctx, &mut builder, ty_string);248    builder.set_relevance(CompletionRelevance {249        type_match: Some(CompletionRelevanceTypeMatch::Exact),250        exact_name_match: true,251        ..Default::default()252    });253    builder.build(ctx.db)254}255256pub(crate) fn render_path_resolution<'db>(257    ctx: RenderContext<'_, 'db>,258    path_ctx: &PathCompletionCtx<'_>,259    local_name: hir::Name,260    resolution: ScopeDef<'db>,261) -> Builder {262    render_resolution_path(ctx, path_ctx, local_name, None, resolution)263}264265pub(crate) fn render_pattern_resolution<'db>(266    ctx: RenderContext<'_, 'db>,267    pattern_ctx: &PatternContext,268    local_name: hir::Name,269    resolution: ScopeDef<'db>,270) -> Builder {271    render_resolution_pat(ctx, pattern_ctx, local_name, None, resolution)272}273274pub(crate) fn render_resolution_with_import(275    ctx: RenderContext<'_, '_>,276    path_ctx: &PathCompletionCtx<'_>,277    import_edit: LocatedImport,278) -> Option<Builder> {279    let resolution = ScopeDef::from(import_edit.original_item);280    let local_name = get_import_name(resolution, &ctx, &import_edit)?;281    // This now just renders the alias text, but we need to find the aliases earlier and call this with the alias instead.282    let doc_aliases = ctx.completion.doc_aliases_in_scope(resolution);283    let ctx = ctx.doc_aliases(doc_aliases);284    Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution))285}286287pub(crate) fn render_resolution_with_import_pat(288    ctx: RenderContext<'_, '_>,289    pattern_ctx: &PatternContext,290    import_edit: LocatedImport,291) -> Option<Builder> {292    let resolution = ScopeDef::from(import_edit.original_item);293    let local_name = get_import_name(resolution, &ctx, &import_edit)?;294    Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution))295}296297pub(crate) fn render_expr<'db>(298    ctx: &CompletionContext<'_, 'db>,299    expr: &hir::term_search::Expr<'db>,300) -> Option<Builder> {301    let mut i = 1;302    let mut snippet_formatter = |ty: &hir::Type<'_>| {303        let arg_name = ty304            .as_adt()305            .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))306            .unwrap_or_else(|| String::from("_"));307        let res = format!("${{{i}:{arg_name}}}");308        i += 1;309        res310    };311312    let mut label_formatter = |ty: &hir::Type<'_>| {313        ty.as_adt()314            .map(|adt| stdx::to_lower_snake_case(adt.name(ctx.db).as_str()))315            .unwrap_or_else(|| String::from("..."))316    };317318    let cfg = ctx.config.find_path_config(ctx.is_nightly);319320    let label =321        expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.display_target).ok()?;322323    let source_range = match ctx.original_token.parent() {324        Some(node) => match node.ancestors().find_map(ast::Path::cast) {325            Some(path) => path.syntax().text_range(),326            None => node.text_range(),327        },328        None => ctx.source_range(),329    };330331    let mut item =332        CompletionItem::new(CompletionItemKind::Expression, source_range, label, ctx.edition);333334    let snippet = format!(335        "{}$0",336        expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg, ctx.display_target).ok()?337    );338    let edit = TextEdit::replace(source_range, snippet);339    item.snippet_edit(ctx.config.snippet_cap?, edit);340    item.documentation(Documentation::new_owned(String::from(341        "Autogenerated expression by term search",342    )));343    item.set_relevance(crate::CompletionRelevance {344        type_match: compute_type_match(ctx, &ctx.rebase_ty(&expr.ty(ctx.db))),345        ..Default::default()346    });347    for trait_ in expr.traits_used(ctx.db) {348        let trait_item = hir::ItemInNs::from(hir::ModuleDef::from(trait_));349        let Some(path) = ctx.module.find_path(ctx.db, trait_item, cfg) else {350            continue;351        };352353        item.add_import(LocatedImport::new_no_completion(path, trait_item, trait_item));354    }355356    Some(item)357}358359fn get_import_name<'db>(360    resolution: ScopeDef<'db>,361    ctx: &RenderContext<'_, 'db>,362    import_edit: &LocatedImport,363) -> Option<hir::Name> {364    // FIXME: Temporary workaround for handling aliased import.365    // This should be removed after we have proper support for importing alias.366    // <https://github.com/rust-lang/rust-analyzer/issues/14079>367368    // If `item_to_import` matches `original_item`, we are importing the item itself (not its parent module).369    // In this case, we can use the last segment of `import_path`, as it accounts for the aliased name.370    if import_edit.item_to_import == import_edit.original_item {371        import_edit.import_path.segments().last().cloned()372    } else {373        scope_def_to_name(resolution, ctx, import_edit)374    }375}376377fn scope_def_to_name<'db>(378    resolution: ScopeDef<'db>,379    ctx: &RenderContext<'_, 'db>,380    import_edit: &LocatedImport,381) -> Option<hir::Name> {382    Some(match resolution {383        ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),384        ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,385        ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),386        _ => item_name(ctx.db(), import_edit.original_item)?,387    })388}389390fn render_resolution_pat<'db>(391    ctx: RenderContext<'_, 'db>,392    pattern_ctx: &PatternContext,393    local_name: hir::Name,394    import_to_add: Option<LocatedImport>,395    resolution: ScopeDef<'db>,396) -> Builder {397    let _p = tracing::info_span!("render_resolution_pat").entered();398    use hir::ModuleDef::*;399400    if let ScopeDef::ModuleDef(Macro(mac)) = resolution {401        let ctx = ctx.import_to_add(import_to_add);402        render_macro_pat(ctx, pattern_ctx, local_name, mac)403    } else {404        render_resolution_simple_(ctx, &local_name, import_to_add, resolution)405    }406}407408fn render_resolution_path<'db>(409    ctx: RenderContext<'_, 'db>,410    path_ctx: &PathCompletionCtx<'_>,411    local_name: hir::Name,412    import_to_add: Option<LocatedImport>,413    resolution: ScopeDef<'db>,414) -> Builder {415    let _p = tracing::info_span!("render_resolution_path").entered();416    use hir::ModuleDef::*;417418    let krate = ctx.completion.display_target;419420    match resolution {421        ScopeDef::ModuleDef(Macro(mac)) => {422            let ctx = ctx.import_to_add(import_to_add);423            return render_macro(ctx, path_ctx, local_name, mac);424        }425        ScopeDef::ModuleDef(Function(func)) => {426            let ctx = ctx.import_to_add(import_to_add);427            return render_fn(ctx, path_ctx, Some(local_name), func);428        }429        ScopeDef::ModuleDef(EnumVariant(var)) => {430            let ctx = ctx.clone().import_to_add(import_to_add.clone());431            if let Some(item) =432                render_variant_lit(ctx, path_ctx, Some(local_name.clone()), var, None)433            {434                return item;435            }436        }437        _ => (),438    }439440    let completion = ctx.completion;441    let module = completion.module;442    let cap = ctx.snippet_cap();443    let db = completion.db;444    let config = completion.config;445    let requires_import = import_to_add.is_some();446447    let name = local_name.display(db, completion.edition).to_smolstr();448    let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution);449    let mut insert_text = name.clone();450451    // Add `<>` for generic types452    let type_path_no_ty_args = matches!(453        path_ctx,454        PathCompletionCtx { kind: PathKind::Type { .. }, has_type_args: false, .. }455    ) && config.callable.is_some();456    if type_path_no_ty_args && let Some(cap) = cap {457        let has_non_default_type_params = match resolution {458            ScopeDef::ModuleDef(hir::ModuleDef::Adt(it)) => it.has_non_default_type_params(db),459            ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(it)) => {460                it.has_non_default_type_params(db)461            }462            _ => false,463        };464465        if has_non_default_type_params {466            cov_mark::hit!(inserts_angle_brackets_for_generics);467            insert_text = format_smolstr!("{insert_text}<$0>");468            item.lookup_by(name.clone())469                .label(SmolStr::from_iter([&name, "<…>"]))470                .trigger_call_info()471                .insert_snippet(cap, ""); // set is snippet472        }473    }474    let allow_module_path = matches!(path_ctx.kind, PathKind::Use)475        || completion.token.next_token().is_some_and(|it| it.kind() == syntax::T![::])476        || !config.add_colons_to_module;477    if !allow_module_path && matches!(resolution, ScopeDef::ModuleDef(Module(_))) {478        insert_text = format_smolstr!("{insert_text}::");479        item.lookup_by(name.clone()).label(insert_text.clone());480    }481    adds_ret_type_arrow(completion, path_ctx, &mut item, insert_text.into());482483    let mut set_item_relevance = |ty: Type<'db>| {484        if !ty.is_unknown() {485            item.detail(ty.display(db, krate).to_string());486        }487488        let ty = completion.rebase_ty(&ty);489        item.set_relevance(CompletionRelevance {490            type_match: compute_type_match(completion, &ty),491            exact_name_match: compute_exact_name_match(completion, &name),492            is_local: matches!(resolution, ScopeDef::Local(_)),493            requires_import,494            has_local_inherent_impl: compute_has_local_inherent_impl(db, path_ctx, &ty, module),495            ..CompletionRelevance::default()496        });497498        match resolution {499            ScopeDef::Local(_)500            | ScopeDef::ModuleDef(ModuleDef::Const(_) | ModuleDef::Static(_)) => {501                path_ref_match(completion, path_ctx, &ty, &mut item)502            }503            _ => (),504        }505    };506507    match resolution {508        ScopeDef::Local(local) => set_item_relevance(local.ty(db)),509        ScopeDef::ModuleDef(ModuleDef::Adt(adt)) | ScopeDef::AdtSelfType(adt) => {510            set_item_relevance(adt.ty(db))511        }512        // Filtered out above513        ScopeDef::ModuleDef(514            ModuleDef::Function(_) | ModuleDef::EnumVariant(_) | ModuleDef::Macro(_),515        ) => (),516        ScopeDef::ModuleDef(ModuleDef::Const(konst)) => set_item_relevance(konst.ty(db)),517        ScopeDef::ModuleDef(ModuleDef::Static(stat)) => set_item_relevance(stat.ty(db)),518        ScopeDef::ModuleDef(ModuleDef::BuiltinType(bt)) => set_item_relevance(bt.ty(db)),519        ScopeDef::ModuleDef(ModuleDef::TypeAlias(ta)) => set_item_relevance(ta.ty(db)),520        ScopeDef::ImplSelfType(imp) => set_item_relevance(imp.self_ty(db)),521        ScopeDef::GenericParam(_)522        | ScopeDef::Label(_)523        | ScopeDef::Unknown524        | ScopeDef::ModuleDef(ModuleDef::Trait(_) | ModuleDef::Module(_)) => (),525    };526527    item528}529530fn render_resolution_simple_<'db>(531    ctx: RenderContext<'_, 'db>,532    local_name: &hir::Name,533    import_to_add: Option<LocatedImport>,534    resolution: ScopeDef<'db>,535) -> Builder {536    let _p = tracing::info_span!("render_resolution_simple_").entered();537538    let db = ctx.db();539    let ctx = ctx.import_to_add(import_to_add);540    let kind = res_to_kind(resolution);541542    let mut item = CompletionItem::new(543        kind,544        ctx.source_range(),545        local_name.as_str().to_smolstr(),546        ctx.completion.edition,547    );548    if let ScopeDef::ModuleDef(ModuleDef::Const(konst)) = resolution {549        item.const_value(Some(konst), db, ctx.completion.display_target);550    }551    item.set_relevance(ctx.completion_relevance())552        .set_documentation(scope_def_docs(db, resolution))553        .set_deprecated(scope_def_is_deprecated(&ctx, resolution));554555    if let Some(import_to_add) = ctx.import_to_add {556        item.add_import(import_to_add);557    }558559    item.doc_aliases(ctx.doc_aliases);560    item561}562563fn res_to_kind(resolution: ScopeDef<'_>) -> CompletionItemKind {564    use hir::ModuleDef::*;565    match resolution {566        ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,567        ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),568        ScopeDef::ModuleDef(EnumVariant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),569        ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro),570        ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),571        ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {572            hir::Adt::Struct(_) => SymbolKind::Struct,573            hir::Adt::Union(_) => SymbolKind::Union,574            hir::Adt::Enum(_) => SymbolKind::Enum,575        }),576        ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),577        ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),578        ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),579        ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::SymbolKind(SymbolKind::TypeAlias),580        ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,581        ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {582            hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,583            hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,584            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,585        }),586        ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),587        ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),588        ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {589            CompletionItemKind::SymbolKind(SymbolKind::SelfParam)590        }591    }592}593594fn scope_def_docs<'db>(595    db: &'db RootDatabase,596    resolution: ScopeDef<'db>,597) -> Option<Documentation<'db>> {598    use hir::ModuleDef::*;599    match resolution {600        ScopeDef::ModuleDef(Module(it)) => it.docs(db),601        ScopeDef::ModuleDef(Adt(it)) => it.docs(db),602        ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(db),603        ScopeDef::ModuleDef(Const(it)) => it.docs(db),604        ScopeDef::ModuleDef(Static(it)) => it.docs(db),605        ScopeDef::ModuleDef(Trait(it)) => it.docs(db),606        ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),607        _ => None,608    }609}610611fn scope_def_is_deprecated(ctx: &RenderContext<'_, '_>, resolution: ScopeDef<'_>) -> bool {612    let db = ctx.db();613    match resolution {614        ScopeDef::ModuleDef(hir::ModuleDef::EnumVariant(it)) => ctx.is_variant_deprecated(it),615        ScopeDef::ModuleDef(it) => ctx.is_deprecated(it, it.as_assoc_item(db)),616        ScopeDef::GenericParam(it) => {617            ctx.is_deprecated(it, None /* generic params can't be assoc items */)618        }619        ScopeDef::AdtSelfType(it) => {620            ctx.is_deprecated(it, None /* `Self` can't be an assoc item */)621        }622        _ => false,623    }624}625626pub(crate) fn render_type_keyword_snippet(627    ctx: &CompletionContext<'_, '_>,628    path_ctx: &PathCompletionCtx<'_>,629    label: &str,630    snippet: &str,631) -> Builder {632    let source_range = ctx.source_range();633    let mut item =634        CompletionItem::new(CompletionItemKind::Keyword, source_range, label, ctx.edition);635636    let insert_text = if !snippet.contains('$') {637        item.insert_text(snippet);638        snippet639    } else if let Some(cap) = ctx.config.snippet_cap {640        item.insert_snippet(cap, snippet);641        snippet642    } else {643        label644    };645646    adds_ret_type_arrow(ctx, path_ctx, &mut item, insert_text.to_owned());647    item648}649650fn adds_ret_type_arrow(651    ctx: &CompletionContext<'_, '_>,652    path_ctx: &PathCompletionCtx<'_>,653    item: &mut Builder,654    insert_text: String,655) {656    if let Some((arrow, at)) = path_ctx.required_thin_arrow(&ctx.sema) {657        let mut edit = TextEdit::builder();658659        edit.insert(at, arrow.to_owned());660        edit.replace(ctx.source_range(), insert_text);661662        item.text_edit(edit.finish()).adds_text(SmolStr::new_static(arrow));663    } else {664        item.insert_text(insert_text);665    }666}667668// FIXME: This checks types without possible coercions which some completions might want to do669fn match_types(670    ctx: &CompletionContext<'_, '_>,671    ty1: &hir::Type<'_>,672    ty2: &hir::Type<'_>,673) -> Option<CompletionRelevanceTypeMatch> {674    if ty1 == ty2 {675        Some(CompletionRelevanceTypeMatch::Exact)676    } else if ty1.could_unify_with(ctx.db, ty2) {677        Some(CompletionRelevanceTypeMatch::CouldUnify)678    } else {679        None680    }681}682683fn compute_type_match(684    ctx: &CompletionContext<'_, '_>,685    completion_ty: &hir::Type<'_>,686) -> Option<CompletionRelevanceTypeMatch> {687    let expected_type = ctx.expected_type.as_ref()?;688689    // We don't ever consider unit type to be an exact type match, since690    // nearly always this is not meaningful to the user.691    if expected_type.is_unit() || completion_ty.is_unit() {692        return None;693    }694    if expected_type.is_unknown() || completion_ty.is_unknown() {695        return None;696    }697698    // &mut ty -> &ty699    if completion_ty.is_mutable_reference()700        && let Some((expected_type, _)) = expected_type.as_reference()701        && let Some((completion_ty, _)) = completion_ty.as_reference()702    {703        return match_types(ctx, &expected_type, &completion_ty);704    }705706    match_types(ctx, expected_type, completion_ty)707}708709fn compute_has_local_inherent_impl(710    db: &RootDatabase,711    path_ctx: &PathCompletionCtx<'_>,712    completion_ty: &hir::Type<'_>,713    curr_module: hir::Module,714) -> bool {715    matches!(path_ctx.kind, PathKind::Type { location: TypeLocation::ImplTarget })716        && Impl::all_for_type(db, completion_ty.clone())717            .iter()718            .any(|imp| imp.trait_(db).is_none() && imp.module(db) == curr_module)719}720721fn compute_exact_name_match(ctx: &CompletionContext<'_, '_>, completion_name: &str) -> bool {722    ctx.expected_name.as_ref().is_some_and(|name| {723        let name = name.text().strip_prefix("r#").unwrap_or(name.text());724        let completion_name = completion_name.strip_prefix("r#").unwrap_or(completion_name);725        name.trim_matches('_') == completion_name.trim_matches('_')726    })727}728729fn compute_ref_match(730    ctx: &CompletionContext<'_, '_>,731    completion_ty: &hir::Type<'_>,732) -> Option<CompletionItemRefMode> {733    if compute_type_match(ctx, completion_ty).is_some() || completion_ty.is_unit() {734        return None;735    }736    let expected_type = ctx.expected_type.as_ref()?;737    let expected_without_ref = expected_type.as_reference();738    let completion_without_ref = completion_ty.as_reference();739740    if let Some((expected_without_ref, _)) = &expected_without_ref741        && (completion_without_ref.is_none()742            || completion_ty.could_unify_with(ctx.db, expected_without_ref))743        && completion_ty744            .autoderef(ctx.db)745            .any(|ty| !ty.is_unknown() && ty.could_unify_with(ctx.db, expected_without_ref))746    {747        cov_mark::hit!(suggest_ref);748        let mutability = if expected_type.is_mutable_reference() {749            hir::Mutability::Mut750        } else {751            hir::Mutability::Shared752        };753        return Some(CompletionItemRefMode::Reference(mutability));754    }755756    if let Some((completion_without_ref, _)) = completion_without_ref757        && completion_without_ref == *expected_type758        && completion_without_ref.is_copy(ctx.db)759    {760        cov_mark::hit!(suggest_deref);761        return Some(CompletionItemRefMode::Dereference);762    }763764    None765}766767fn path_ref_match(768    completion: &CompletionContext<'_, '_>,769    path_ctx: &PathCompletionCtx<'_>,770    ty: &hir::Type<'_>,771    item: &mut Builder,772) {773    if let Some(original_path) = &path_ctx.original_path {774        // At least one char was typed by the user already, in that case look for the original path775        if let Some(original_path) = completion.sema.original_range_opt(original_path.syntax())776            && let Some(ref_mode) = compute_ref_match(completion, ty)777        {778            item.ref_match(ref_mode, original_path.range.start());779        }780    } else {781        // completion requested on an empty identifier, there is no path here yet.782        // FIXME: This might create inconsistent completions where we show a ref match in macro inputs783        // as long as nothing was typed yet784        if let Some(ref_mode) = compute_ref_match(completion, ty) {785            item.ref_match(ref_mode, completion.source_range().start());786        }787    }788}789790#[cfg(test)]791mod tests {792    use std::cmp;793794    use expect_test::{Expect, expect};795    use ide_db::SymbolKind;796    use itertools::Itertools;797798    use crate::{799        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,800        item::CompletionRelevanceTypeMatch,801        tests::{TEST_CONFIG, check_edit, do_completion, get_all_items},802    };803804    #[track_caller]805    fn check(806        #[rust_analyzer::rust_fixture] ra_fixture: &str,807        kind: impl Into<CompletionItemKind>,808        expect: Expect,809    ) {810        let actual = do_completion(ra_fixture, kind.into());811        expect.assert_debug_eq(&actual);812    }813814    #[track_caller]815    fn check_kinds(816        #[rust_analyzer::rust_fixture] ra_fixture: &str,817        kinds: &[CompletionItemKind],818        expect: Expect,819    ) {820        let actual: Vec<_> =821            kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect();822        expect.assert_debug_eq(&actual);823    }824825    #[track_caller]826    fn check_function_relevance(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {827        let actual: Vec<_> =828            do_completion(ra_fixture, CompletionItemKind::SymbolKind(SymbolKind::Method))829                .into_iter()830                .map(|item| (item.detail.unwrap_or_default(), item.relevance.function))831                .collect();832833        expect.assert_debug_eq(&actual);834    }835836    #[track_caller]837    fn check_relevance_for_kinds(838        #[rust_analyzer::rust_fixture] ra_fixture: &str,839        kinds: &[CompletionItemKind],840        expect: Expect,841    ) {842        let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);843        actual.retain(|it| kinds.contains(&it.kind));844        actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone()));845        check_relevance_(actual, expect);846    }847848    #[track_caller]849    fn check_relevance(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {850        let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None);851        actual.retain(|it| it.kind != CompletionItemKind::Snippet);852        actual.retain(|it| it.kind != CompletionItemKind::Keyword);853        actual.retain(|it| it.kind != CompletionItemKind::BuiltinType);854        actual.sort_by_key(|it| (cmp::Reverse(it.relevance.score()), it.label.primary.clone()));855        check_relevance_(actual, expect);856    }857858    #[track_caller]859    fn check_relevance_(actual: Vec<CompletionItem>, expect: Expect) {860        let actual = actual861            .into_iter()862            .flat_map(|it| {863                let mut items = vec![];864865                let tag = it.kind.tag();866                let relevance = display_relevance(it.relevance);867                items.push(format!(868                    "{tag} {} {} {relevance}\n",869                    it.label.primary,870                    it.label.detail_right.as_deref().unwrap_or_default(),871                ));872873                if let Some((label, _indel, relevance)) = it.ref_match() {874                    let relevance = display_relevance(relevance);875876                    items.push(format!("{tag} {label} {relevance}\n"));877                }878879                items880            })881            .collect::<String>();882883        expect.assert_eq(&actual);884885        fn display_relevance(relevance: CompletionRelevance) -> String {886            let CompletionRelevance {887                exact_name_match,888                type_match,889                is_local,890                is_missing,891                trait_,892                is_name_already_imported: _,893                requires_import,894                is_private_editable: _,895                postfix_match,896                function: _,897                is_skipping_completion: _,898                has_local_inherent_impl,899                is_deprecated,900            } = relevance;901            let relevance_factors = [902                (type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),903                (type_match == Some(CompletionRelevanceTypeMatch::CouldUnify), "type_could_unify"),904                (exact_name_match, "name"),905                (is_local, "local"),906                (is_missing, "missing"),907                (postfix_match == Some(CompletionRelevancePostfixMatch::Exact), "snippet"),908                (trait_.is_some_and(|it| it.is_op_method), "op_method"),909                (requires_import, "requires_import"),910                (has_local_inherent_impl, "has_local_inherent_impl"),911                (is_deprecated, "deprecated"),912            ]913            .into_iter()914            .filter_map(|(cond, desc)| cond.then_some(desc))915            .join("+");916917            format!("[{relevance_factors}]")918        }919    }920921    #[test]922    fn trait_imported_as_underscore_should_not_appear_auto_import_again() {923        // make sure there has no `requires_import`924        // see https://github.com/rust-lang/rust-analyzer/issues/19767925        check_relevance(926            r#"927//- /dep.rs crate:dep928pub trait MyTrait {929    fn my_method(&self);930}931932//- /main.rs crate:main deps:dep933use dep::MyTrait as _;934struct MyStruct;935impl dep::MyTrait for MyStruct {936    fn my_method(&self) {}937}938fn main() {939    MyStruct::my_method$0940}941"#,942            expect![[r#"943                me my_method(…) fn(&self) []944            "#]],945        );946    }947948    #[test]949    fn set_struct_type_completion_info() {950        check_relevance(951            r#"952//- /lib.rs crate:dep953954pub mod test_mod_b {955    pub struct Struct {}956}957958pub mod test_mod_a {959    pub struct Struct {}960}961962//- /main.rs crate:main deps:dep963964fn test(input: dep::test_mod_b::Struct) { }965966fn main() {967    test(Struct$0);968}969"#,970            expect![[r#"971                st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct {  } [type]972                ex dep::test_mod_b::Struct {  }  [type]973                st Struct Struct [type+requires_import]974                md dep::  []975                fn main() fn() []976                fn test(…) fn(Struct) []977                st Struct Struct [requires_import]978            "#]],979        );980    }981982    #[test]983    fn set_union_type_completion_info() {984        check_relevance(985            r#"986//- /lib.rs crate:dep987988pub mod test_mod_b {989    pub union Union {990        a: i32,991        b: i32992    }993}994995pub mod test_mod_a {996    pub enum Union {997        a: i32,998        b: i32999    }1000}10011002//- /main.rs crate:main deps:dep10031004fn test(input: dep::test_mod_b::Union) { }10051006fn main() {1007    test(Union$0);1008}1009"#,1010            expect![[r#"1011                un Union Union [type+requires_import]1012                md dep::  []1013                fn main() fn() []1014                fn test(…) fn(Union) []1015                en Union Union [requires_import]1016            "#]],1017        );1018    }10191020    #[test]1021    fn set_enum_type_completion_info() {1022        check_relevance(1023            r#"1024//- /lib.rs crate:dep10251026pub mod test_mod_b {1027    pub enum Enum {1028        variant1029    }1030}10311032pub mod test_mod_a {1033    pub enum Enum {1034        variant1035    }1036}10371038//- /main.rs crate:main deps:dep10391040fn test(input: dep::test_mod_b::Enum) { }10411042fn main() {1043    test(Enum$0);1044}1045"#,1046            expect![[r#"1047                ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type]1048                ex dep::test_mod_b::Enum::variant  [type]1049                en Enum Enum [type+requires_import]1050                md dep::  []1051                fn main() fn() []1052                fn test(…) fn(Enum) []1053                en Enum Enum [requires_import]1054            "#]],1055        );1056    }10571058    #[test]1059    fn set_enum_variant_type_completion_info() {1060        check_relevance(1061            r#"1062//- /lib.rs crate:dep10631064pub mod test_mod_b {1065    pub enum Enum {1066        Variant1067    }1068}10691070pub mod test_mod_a {1071    pub enum Enum {1072        Variant1073    }1074}10751076//- /main.rs crate:main deps:dep10771078fn test(input: dep::test_mod_b::Enum) { }10791080fn main() {1081    test(Variant$0);1082}1083"#,1084            expect![[r#"1085                ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type]1086                ex dep::test_mod_b::Enum::Variant  [type]1087                ev Variant Variant [type+requires_import]1088                md dep::  []1089                fn main() fn() []1090                fn test(…) fn(Enum) []1091                ev Variant Variant [requires_import]1092            "#]],1093        );1094    }10951096    #[test]1097    fn set_fn_type_completion_info() {1098        check_relevance(1099            r#"1100//- /lib.rs crate:dep11011102pub mod test_mod_b {1103    pub fn function(j: isize) -> i32 {}1104}11051106pub mod test_mod_a {1107    pub fn function(i: usize) -> i32 {}1108}11091110//- /main.rs crate:main deps:dep11111112fn test(input: fn(usize) -> i32) { }11131114fn main() {1115    test(function$0);1116}1117"#,1118            expect![[r#"1119                md dep::  []1120                fn main() fn() []1121                fn test(…) fn(fn(usize) -> i32) []1122                fn function fn(usize) -> i32 [requires_import]1123                fn function(…) fn(isize) -> i32 [requires_import]1124            "#]],1125        );1126    }11271128    #[test]1129    fn set_const_type_completion_info() {1130        check_relevance(1131            r#"1132//- /lib.rs crate:dep11331134pub mod test_mod_b {1135    pub const CONST: i32 = 1;1136}11371138pub mod test_mod_a {1139    pub const CONST: i64 = 2;1140}11411142//- /main.rs crate:main deps:dep11431144fn test(input: i32) { }11451146fn main() {1147    test(CONST$0);1148}1149"#,1150            expect![[r#"1151                ct CONST i32 [type+requires_import]1152                md dep::  []1153                fn main() fn() []1154                fn test(…) fn(i32) []1155                ct CONST i64 [requires_import]1156            "#]],1157        );1158    }11591160    #[test]1161    fn set_static_type_completion_info() {1162        check_relevance(1163            r#"1164//- /lib.rs crate:dep11651166pub mod test_mod_b {1167    pub static STATIC: i32 = 5;1168}11691170pub mod test_mod_a {1171    pub static STATIC: i64 = 5;1172}11731174//- /main.rs crate:main deps:dep11751176fn test(input: i32) { }11771178fn main() {1179    test(STATIC$0);1180}1181"#,1182            expect![[r#"1183                sc STATIC i32 [type+requires_import]1184                md dep::  []1185                fn main() fn() []1186                fn test(…) fn(i32) []1187                sc STATIC i64 [requires_import]1188            "#]],1189        );1190    }11911192    #[test]1193    fn set_self_type_completion_info_with_params() {1194        check_relevance(1195            r#"1196//- /lib.rs crate:dep1197pub struct Struct;11981199impl Struct {1200    pub fn Function(&self, input: i32) -> bool {1201                false1202    }1203}120412051206//- /main.rs crate:main deps:dep12071208use dep::Struct;120912101211fn test(input: fn(&dep::Struct, i32) -> bool) { }12121213fn main() {1214    test(Struct::Function$0);1215}12161217"#,1218            expect![[r#"1219                me Function fn(&self, i32) -> bool []1220            "#]],1221        );1222    }12231224    #[test]1225    fn set_self_type_completion_info() {1226        check_relevance(1227            r#"1228//- /main.rs crate:main12291230struct Struct;12311232impl Struct {1233fn test(&self) {1234        func(Self$0);1235    }1236}12371238fn func(input: Struct) { }12391240"#,1241            expect![[r#"1242                st Self Self [type]1243                st Struct Struct [type]1244                sp Self Struct [type]1245                st Struct Struct [type]1246                ex Struct  [type]1247                lc self &Struct [local]1248                fn func(…) fn(Struct) []1249                me self.test() fn(&self) []1250            "#]],1251        );1252    }12531254    #[test]1255    fn set_type_alias_completion_info() {1256        check_relevance(1257            r#"1258//- /main.rs crate:main1259struct Struct;1260type Alias = Struct;12611262impl Struct {1263    fn test(&self) {1264        func(Self$0);1265    }1266}1267fn func(input: Struct) { }1268"#,1269            expect![[r#"1270                st Self Self [type]1271                st Struct Struct [type]1272                ta Alias Struct [type]1273                sp Self Struct [type]1274                st Struct Struct [type]1275                ex Struct  [type]1276                lc self &Struct [local]1277                fn func(…) fn(Struct) []1278                me self.test() fn(&self) []1279            "#]],1280        );1281    }12821283    #[test]1284    fn set_builtin_type_completion_info() {1285        check_relevance(1286            r#"1287//- /main.rs crate:main12881289fn test(input: bool) { }1290    pub Input: bool = false;12911292fn main() {1293    let input = false;1294    let inputbad = 3;1295    test(inp$0);1296}1297"#,1298            expect![[r#"1299                lc input bool [type+name+local]1300                ex false  [type]1301                ex input  [type]1302                ex true  [type]1303                lc inputbad i32 [local]1304                fn main() fn() []1305                fn test(…) fn(bool) []1306            "#]],1307        );1308    }13091310    #[test]1311    fn enum_detail_includes_record_fields() {1312        check(1313            r#"1314enum Foo { Foo { x: i32, y: i32 } }13151316fn main() { Foo::Fo$0 }1317"#,1318            SymbolKind::Variant,1319            expect![[r#"1320                [1321                    CompletionItem {1322                        label: "Foo {…}",1323                        detail_left: None,1324                        detail_right: Some(1325                            "Foo { x: i32, y: i32 }",1326                        ),1327                        source_range: 54..56,1328                        delete: 54..56,1329                        insert: "Foo { x: ${1:()}, y: ${2:()} }$0",1330                        kind: SymbolKind(1331                            Variant,1332                        ),1333                        lookup: "Foo{}",1334                        detail: "Foo { x: i32, y: i32 }",1335                        relevance: CompletionRelevance {1336                            exact_name_match: false,1337                            type_match: None,1338                            is_local: false,1339                            is_missing: false,1340                            trait_: None,1341                            is_name_already_imported: false,1342                            requires_import: false,1343                            is_private_editable: false,1344                            postfix_match: None,1345                            function: Some(1346                                CompletionRelevanceFn {1347                                    has_params: true,1348                                    has_self_param: false,1349                                    return_type: DirectConstructor,1350                                },1351                            ),1352                            is_skipping_completion: false,1353                            has_local_inherent_impl: false,1354                            is_deprecated: false,1355                        },1356                        trigger_call_info: true,1357                    },1358                ]1359            "#]],1360        );1361    }13621363    #[test]1364    fn enum_detail_includes_tuple_fields() {1365        check(1366            r#"1367enum Foo { Foo (i32, i32) }13681369fn main() { Foo::Fo$0 }1370"#,1371            SymbolKind::Variant,1372            expect![[r#"1373                [1374                    CompletionItem {1375                        label: "Foo(…)",1376                        detail_left: None,1377                        detail_right: Some(1378                            "Foo(i32, i32)",1379                        ),1380                        source_range: 46..48,1381                        delete: 46..48,1382                        insert: "Foo(${1:()}, ${2:()})$0",1383                        kind: SymbolKind(1384                            Variant,1385                        ),1386                        lookup: "Foo()",1387                        detail: "Foo(i32, i32)",1388                        relevance: CompletionRelevance {1389                            exact_name_match: false,1390                            type_match: None,1391                            is_local: false,1392                            is_missing: false,1393                            trait_: None,1394                            is_name_already_imported: false,1395                            requires_import: false,1396                            is_private_editable: false,1397                            postfix_match: None,1398                            function: Some(1399                                CompletionRelevanceFn {1400                                    has_params: true,1401                                    has_self_param: false,1402                                    return_type: DirectConstructor,1403                                },1404                            ),1405                            is_skipping_completion: false,1406                            has_local_inherent_impl: false,1407                            is_deprecated: false,1408                        },1409                        trigger_call_info: true,1410                    },1411                ]1412            "#]],1413        );1414    }14151416    #[test]1417    fn fn_detail_includes_args_and_return_type() {1418        check(1419            r#"1420fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }14211422fn main() { fo$0 }1423"#,1424            SymbolKind::Function,1425            expect![[r#"1426                [1427                    CompletionItem {1428                        label: "foo(…)",1429                        detail_left: None,1430                        detail_right: Some(1431                            "fn(u32, u32, T) -> (u32, T)",1432                        ),1433                        source_range: 68..70,1434                        delete: 68..70,1435                        insert: "foo(${1:a}, ${2:b}, ${3:t})$0",1436                        kind: SymbolKind(1437                            Function,1438                        ),1439                        lookup: "foo",1440                        detail: "fn(u32, u32, T) -> (u32, T)",1441                        trigger_call_info: true,1442                    },1443                    CompletionItem {1444                        label: "main()",1445                        detail_left: None,1446                        detail_right: Some(1447                            "fn()",1448                        ),1449                        source_range: 68..70,1450                        delete: 68..70,1451                        insert: "main();$0",1452                        kind: SymbolKind(1453                            Function,1454                        ),1455                        lookup: "main",1456                        detail: "fn()",1457                    },1458                ]1459            "#]],1460        );1461    }14621463    #[test]1464    fn fn_detail_includes_variadics() {1465        check(1466            r#"1467unsafe extern "C" fn foo(a: u32, b: u32, ...) {}14681469fn main() { fo$0 }1470"#,1471            SymbolKind::Function,1472            expect![[r#"1473                [1474                    CompletionItem {1475                        label: "foo(…)",1476                        detail_left: None,1477                        detail_right: Some(1478                            "unsafe fn(u32, u32, ...)",1479                        ),1480                        source_range: 62..64,1481                        delete: 62..64,1482                        insert: "foo(${1:a}, ${2:b});$0",1483                        kind: SymbolKind(1484                            Function,1485                        ),1486                        lookup: "foo",1487                        detail: "unsafe fn(u32, u32, ...)",1488                        trigger_call_info: true,1489                    },1490                    CompletionItem {1491                        label: "main()",1492                        detail_left: None,1493                        detail_right: Some(1494                            "fn()",1495                        ),1496                        source_range: 62..64,1497                        delete: 62..64,1498                        insert: "main();$0",1499                        kind: SymbolKind(1500                            Function,1501                        ),1502                        lookup: "main",1503                        detail: "fn()",1504                    },1505                ]1506            "#]],1507        );1508    }15091510    #[test]1511    fn enum_detail_just_name_for_unit() {1512        check(1513            r#"1514enum Foo { Foo }15151516fn main() { Foo::Fo$0 }1517"#,1518            SymbolKind::Variant,1519            expect![[r#"1520                [1521                    CompletionItem {1522                        label: "Foo",1523                        detail_left: None,1524                        detail_right: Some(1525                            "Foo",1526                        ),1527                        source_range: 35..37,1528                        delete: 35..37,1529                        insert: "Foo$0",1530                        kind: SymbolKind(1531                            Variant,1532                        ),1533                        detail: "Foo",1534                        relevance: CompletionRelevance {1535                            exact_name_match: false,1536                            type_match: None,1537                            is_local: false,1538                            is_missing: false,1539                            trait_: None,1540                            is_name_already_imported: false,1541                            requires_import: false,1542                            is_private_editable: false,1543                            postfix_match: None,1544                            function: Some(1545                                CompletionRelevanceFn {1546                                    has_params: false,1547                                    has_self_param: false,1548                                    return_type: DirectConstructor,1549                                },1550                            ),1551                            is_skipping_completion: false,1552                            has_local_inherent_impl: false,1553                            is_deprecated: false,1554                        },1555                        trigger_call_info: true,1556                    },1557                ]1558            "#]],1559        );1560    }15611562    #[test]1563    fn lookup_enums_by_two_qualifiers() {1564        check_kinds(1565            r#"1566mod m {1567    pub enum Spam { Foo, Bar(i32) }1568}1569fn main() { let _: m::Spam = S$0 }1570"#,1571            &[1572                CompletionItemKind::SymbolKind(SymbolKind::Function),1573                CompletionItemKind::SymbolKind(SymbolKind::Module),1574                CompletionItemKind::SymbolKind(SymbolKind::Variant),1575            ],1576            expect![[r#"1577                [1578                    CompletionItem {1579                        label: "main()",1580                        detail_left: None,1581                        detail_right: Some(1582                            "fn()",1583                        ),1584                        source_range: 75..76,1585                        delete: 75..76,1586                        insert: "main();$0",1587                        kind: SymbolKind(1588                            Function,1589                        ),1590                        lookup: "main",1591                        detail: "fn()",1592                    },1593                    CompletionItem {1594                        label: "m::",1595                        detail_left: None,1596                        detail_right: None,1597                        source_range: 75..76,1598                        delete: 75..76,1599                        insert: "m::",1600                        kind: SymbolKind(1601                            Module,1602                        ),1603                        lookup: "m",1604                    },1605                    CompletionItem {1606                        label: "m::Spam::Bar(…)",1607                        detail_left: None,1608                        detail_right: Some(1609                            "m::Spam::Bar(i32)",1610                        ),1611                        source_range: 75..76,1612                        delete: 75..76,1613                        insert: "m::Spam::Bar(${1:()})$0",1614                        kind: SymbolKind(1615                            Variant,1616                        ),1617                        lookup: "Spam::Bar()",1618                        detail: "m::Spam::Bar(i32)",1619                        relevance: CompletionRelevance {1620                            exact_name_match: false,1621                            type_match: Some(1622                                Exact,1623                            ),1624                            is_local: false,1625                            is_missing: false,1626                            trait_: None,1627                            is_name_already_imported: false,1628                            requires_import: false,1629                            is_private_editable: false,1630                            postfix_match: None,1631                            function: Some(1632                                CompletionRelevanceFn {1633                                    has_params: true,1634                                    has_self_param: false,1635                                    return_type: DirectConstructor,1636                                },1637                            ),1638                            is_skipping_completion: false,1639                            has_local_inherent_impl: false,1640                            is_deprecated: false,1641                        },1642                        trigger_call_info: true,1643                    },1644                    CompletionItem {1645                        label: "m::Spam::Foo",1646                        detail_left: None,1647                        detail_right: Some(1648                            "m::Spam::Foo",1649                        ),1650                        source_range: 75..76,1651                        delete: 75..76,1652                        insert: "m::Spam::Foo$0",1653                        kind: SymbolKind(1654                            Variant,1655                        ),1656                        lookup: "Spam::Foo",1657                        detail: "m::Spam::Foo",1658                        relevance: CompletionRelevance {1659                            exact_name_match: false,1660                            type_match: Some(1661                                Exact,1662                            ),1663                            is_local: false,1664                            is_missing: false,1665                            trait_: None,1666                            is_name_already_imported: false,1667                            requires_import: false,1668                            is_private_editable: false,1669                            postfix_match: None,1670                            function: Some(1671                                CompletionRelevanceFn {1672                                    has_params: false,1673                                    has_self_param: false,1674                                    return_type: DirectConstructor,1675                                },1676                            ),1677                            is_skipping_completion: false,1678                            has_local_inherent_impl: false,1679                            is_deprecated: false,1680                        },1681                        trigger_call_info: true,1682                    },1683                ]1684            "#]],1685        )1686    }16871688    #[test]1689    fn sets_deprecated_flag_in_items() {1690        check(1691            r#"1692#[deprecated]1693mod something_deprecated {}16941695fn main() { som$0 }1696"#,1697            SymbolKind::Module,1698            expect![[r#"1699                [1700                    CompletionItem {1701                        label: "something_deprecated::",1702                        detail_left: None,1703                        detail_right: None,1704                        source_range: 55..58,1705                        delete: 55..58,1706                        insert: "something_deprecated::",1707                        kind: SymbolKind(1708                            Module,1709                        ),1710                        lookup: "something_deprecated",1711                        deprecated: true,1712                        relevance: CompletionRelevance {1713                            exact_name_match: false,1714                            type_match: None,1715                            is_local: false,1716                            is_missing: false,1717                            trait_: None,1718                            is_name_already_imported: false,1719                            requires_import: false,1720                            is_private_editable: false,1721                            postfix_match: None,1722                            function: None,1723                            is_skipping_completion: false,1724                            has_local_inherent_impl: false,1725                            is_deprecated: true,1726                        },1727                    },1728                ]1729            "#]],1730        );17311732        check(1733            r#"1734#[deprecated]1735fn something_deprecated() {}17361737fn main() { som$0 }1738"#,1739            SymbolKind::Function,1740            expect![[r#"1741                [1742                    CompletionItem {1743                        label: "main()",1744                        detail_left: None,1745                        detail_right: Some(1746                            "fn()",1747                        ),1748                        source_range: 56..59,1749                        delete: 56..59,1750                        insert: "main();$0",1751                        kind: SymbolKind(1752                            Function,1753                        ),1754                        lookup: "main",1755                        detail: "fn()",1756                    },1757                    CompletionItem {1758                        label: "something_deprecated()",1759                        detail_left: None,1760                        detail_right: Some(1761                            "fn()",1762                        ),1763                        source_range: 56..59,1764                        delete: 56..59,1765                        insert: "something_deprecated();$0",1766                        kind: SymbolKind(1767                            Function,1768                        ),1769                        lookup: "something_deprecated",1770                        detail: "fn()",1771                        deprecated: true,1772                        relevance: CompletionRelevance {1773                            exact_name_match: false,1774                            type_match: None,1775                            is_local: false,1776                            is_missing: false,1777                            trait_: None,1778                            is_name_already_imported: false,1779                            requires_import: false,1780                            is_private_editable: false,1781                            postfix_match: None,1782                            function: None,1783                            is_skipping_completion: false,1784                            has_local_inherent_impl: false,1785                            is_deprecated: true,1786                        },1787                    },1788                ]1789            "#]],1790        );17911792        check(1793            r#"1794#[deprecated]1795struct A;17961797fn main() { A$0 }1798"#,1799            SymbolKind::Struct,1800            expect![[r#"1801                [1802                    CompletionItem {1803                        label: "A",1804                        detail_left: None,1805                        detail_right: Some(1806                            "A",1807                        ),1808                        source_range: 37..38,1809                        delete: 37..38,1810                        insert: "A",1811                        kind: SymbolKind(1812                            Struct,1813                        ),1814                        detail: "A",1815                        deprecated: true,1816                        relevance: CompletionRelevance {1817                            exact_name_match: false,1818                            type_match: None,1819                            is_local: false,1820                            is_missing: false,1821                            trait_: None,1822                            is_name_already_imported: false,1823                            requires_import: false,1824                            is_private_editable: false,1825                            postfix_match: None,1826                            function: None,1827                            is_skipping_completion: false,1828                            has_local_inherent_impl: false,1829                            is_deprecated: true,1830                        },1831                    },1832                ]1833            "#]],1834        );18351836        check(1837            r#"1838#[deprecated]1839enum A {}18401841fn main() { A$0 }1842"#,1843            SymbolKind::Enum,1844            expect![[r#"1845                [1846                    CompletionItem {1847                        label: "A",1848                        detail_left: None,1849                        detail_right: Some(1850                            "A",1851                        ),1852                        source_range: 37..38,1853                        delete: 37..38,1854                        insert: "A",1855                        kind: SymbolKind(1856                            Enum,1857                        ),1858                        detail: "A",1859                        deprecated: true,1860                        relevance: CompletionRelevance {1861                            exact_name_match: false,1862                            type_match: None,1863                            is_local: false,1864                            is_missing: false,1865                            trait_: None,1866                            is_name_already_imported: false,1867                            requires_import: false,1868                            is_private_editable: false,1869                            postfix_match: None,1870                            function: None,1871                            is_skipping_completion: false,1872                            has_local_inherent_impl: false,1873                            is_deprecated: true,1874                        },1875                    },1876                ]1877            "#]],1878        );18791880        check(1881            r#"1882enum A {1883    Okay,1884    #[deprecated]1885    Old,1886}18871888fn main() { A::$0 }1889"#,1890            SymbolKind::Variant,1891            expect![[r#"1892                [1893                    CompletionItem {1894                        label: "Okay",1895                        detail_left: None,1896                        detail_right: Some(1897                            "Okay",1898                        ),1899                        source_range: 64..64,1900                        delete: 64..64,1901                        insert: "Okay$0",1902                        kind: SymbolKind(1903                            Variant,1904                        ),1905                        detail: "Okay",1906                        relevance: CompletionRelevance {1907                            exact_name_match: false,1908                            type_match: None,1909                            is_local: false,1910                            is_missing: false,1911                            trait_: None,1912                            is_name_already_imported: false,1913                            requires_import: false,1914                            is_private_editable: false,1915                            postfix_match: None,1916                            function: Some(1917                                CompletionRelevanceFn {1918                                    has_params: false,1919                                    has_self_param: false,1920                                    return_type: DirectConstructor,1921                                },1922                            ),1923                            is_skipping_completion: false,1924                            has_local_inherent_impl: false,1925                            is_deprecated: false,1926                        },1927                        trigger_call_info: true,1928                    },1929                    CompletionItem {1930                        label: "Old",1931                        detail_left: None,1932                        detail_right: Some(1933                            "Old",1934                        ),1935                        source_range: 64..64,1936                        delete: 64..64,1937                        insert: "Old$0",1938                        kind: SymbolKind(1939                            Variant,1940                        ),1941                        detail: "Old",1942                        deprecated: true,1943                        relevance: CompletionRelevance {1944                            exact_name_match: false,1945                            type_match: None,1946                            is_local: false,1947                            is_missing: false,1948                            trait_: None,1949                            is_name_already_imported: false,1950                            requires_import: false,1951                            is_private_editable: false,1952                            postfix_match: None,1953                            function: Some(1954                                CompletionRelevanceFn {1955                                    has_params: false,1956                                    has_self_param: false,1957                                    return_type: DirectConstructor,1958                                },1959                            ),1960                            is_skipping_completion: false,1961                            has_local_inherent_impl: false,1962                            is_deprecated: true,1963                        },1964                        trigger_call_info: true,1965                    },1966                ]1967            "#]],1968        );19691970        check(1971            r#"1972#[deprecated]1973const A: i32 = 0;19741975fn main() { A$0 }1976"#,1977            SymbolKind::Const,1978            expect![[r#"1979                [1980                    CompletionItem {1981                        label: "A",1982                        detail_left: Some(1983                            " = 0",1984                        ),1985                        detail_right: Some(1986                            "i32",1987                        ),1988                        source_range: 45..46,1989                        delete: 45..46,1990                        insert: "A",1991                        kind: SymbolKind(1992                            Const,1993                        ),1994                        detail: "i32",1995                        deprecated: true,1996                        relevance: CompletionRelevance {1997                            exact_name_match: false,1998                            type_match: None,1999                            is_local: false,2000                            is_missing: false,

Findings

✓ No findings reported for this file.

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