src/tools/rust-analyzer/crates/ide/src/signature_help.rs RUST 2,669 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,669.
1//! This module provides primitives for showing type and function parameter information when editing2//! a call or use-site.34use std::collections::BTreeSet;56use either::Either;7use hir::{8    AssocItem, DisplayTarget, GenericDef, GenericParam, HirDisplay, ModuleDef, PathResolution,9    Semantics, Trait,10};11use ide_db::{12    FilePosition, FxIndexMap,13    active_parameter::{callable_for_arg_list, generic_def_for_node},14    documentation::{Documentation, HasDocs},15};16use itertools::Itertools;17use span::Edition;18use stdx::format_to;19use syntax::{20    AstNode, Direction, NodeOrToken, SyntaxElementChildren, SyntaxNode, SyntaxToken, T, TextRange,21    TextSize, ToSmolStr, algo,22    ast::{self, AstChildren},23    match_ast,24};2526use crate::RootDatabase;2728/// Contains information about an item signature as seen from a use site.29///30/// This includes the "active parameter", which is the parameter whose value is currently being31/// edited.32#[derive(Debug)]33pub struct SignatureHelp {34    pub doc: Option<Documentation<'static>>,35    pub signature: String,36    pub active_parameter: Option<usize>,37    parameters: Vec<TextRange>,38}3940impl SignatureHelp {41    pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {42        self.parameters.iter().map(move |&it| &self.signature[it])43    }4445    pub fn parameter_ranges(&self) -> &[TextRange] {46        &self.parameters47    }4849    fn push_call_param(&mut self, param: &str) {50        self.push_param("(", param);51    }5253    fn push_generic_param(&mut self, param: &str) {54        self.push_param("<", param);55    }5657    fn push_record_field(&mut self, param: &str) {58        self.push_param("{ ", param);59    }6061    fn push_param(&mut self, opening_delim: &str, param: &str) {62        if !self.signature.ends_with(opening_delim) {63            self.signature.push_str(", ");64        }65        let start = TextSize::of(&self.signature);66        self.signature.push_str(param);67        let end = TextSize::of(&self.signature);68        self.parameters.push(TextRange::new(start, end))69    }70}7172/// Computes parameter information for the given position.73pub(crate) fn signature_help(74    db: &RootDatabase,75    FilePosition { file_id, offset }: FilePosition,76) -> Option<SignatureHelp> {77    let sema = Semantics::new(db);78    let file = sema.parse_guess_edition(file_id);79    let file = file.syntax();80    let token = file81        .token_at_offset(offset)82        .left_biased()83        // if the cursor is sandwiched between two space tokens and the call is unclosed84        // this prevents us from leaving the CallExpression85        .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;86    let token = sema.descend_into_macros_single_exact(token);87    let edition = sema.attach_first_edition(file_id).edition(db);88    let display_target = sema.first_crate(file_id)?.to_display_target(db);8990    for node in token.parent_ancestors() {91        match_ast! {92            match node {93                ast::ArgList(arg_list) => {94                    let cursor_outside = arg_list.r_paren_token().as_ref() == Some(&token);95                    if cursor_outside {96                        continue;97                    }98                    return signature_help_for_call(&sema, arg_list, token, edition, display_target);99                },100                ast::GenericArgList(garg_list) => {101                    let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token);102                    if cursor_outside {103                        continue;104                    }105                    return signature_help_for_generics(&sema, garg_list, token, edition, display_target);106                },107                ast::RecordExpr(record) => {108                    let cursor_outside = record.record_expr_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);109                    if cursor_outside {110                        continue;111                    }112                    return signature_help_for_record_lit(&sema, record, token, edition, display_target);113                },114                ast::RecordPat(record) => {115                    let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);116                    if cursor_outside {117                        continue;118                    }119                    return signature_help_for_record_pat(&sema, record, token, edition, display_target);120                },121                ast::TupleStructPat(tuple_pat) => {122                    let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);123                    if cursor_outside {124                        continue;125                    }126                    return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition, display_target);127                },128                ast::TuplePat(tuple_pat) => {129                    let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);130                    if cursor_outside {131                        continue;132                    }133                    return signature_help_for_tuple_pat(&sema, tuple_pat, token, display_target);134                },135                ast::TupleExpr(tuple_expr) => {136                    let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token);137                    if cursor_outside {138                        continue;139                    }140                    return signature_help_for_tuple_expr(&sema, tuple_expr, token, display_target);141                },142                _ => (),143            }144        }145146        // Stop at multi-line expressions, since the signature of the outer call is not very147        // helpful inside them.148        if let Some(expr) = ast::Expr::cast(node.clone())149            && !matches!(expr, ast::Expr::RecordExpr(..))150            && expr.syntax().text().contains_char('\n')151        {152            break;153        }154    }155156    None157}158159fn signature_help_for_call(160    sema: &Semantics<'_, RootDatabase>,161    arg_list: ast::ArgList,162    token: SyntaxToken,163    edition: Edition,164    display_target: DisplayTarget,165) -> Option<SignatureHelp> {166    let (callable, active_parameter) =167        callable_for_arg_list(sema, arg_list, token.text_range().start())?;168169    let mut res =170        SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };171172    let db = sema.db;173    let mut fn_params = None;174    match callable.kind() {175        hir::CallableKind::Function(func) => {176            res.doc = func.docs(db).map(Documentation::into_owned);177            if func.is_async(db) {178                format_to!(res.signature, "async ");179            }180            format_to!(res.signature, "fn {}", func.name(db).display(db, edition));181182            let generic_params = GenericDef::Function(func)183                .params(db)184                .iter()185                .filter(|param| match param {186                    GenericParam::TypeParam(type_param) => !type_param.is_implicit(db),187                    GenericParam::ConstParam(_) | GenericParam::LifetimeParam(_) => true,188                })189                .map(|param| param.display(db, display_target))190                .join(", ");191            if !generic_params.is_empty() {192                format_to!(res.signature, "<{}>", generic_params);193            }194195            fn_params = Some(match callable.receiver_param(db) {196                Some(_self) => func.params_without_self(db),197                None => func.assoc_fn_params(db),198            });199        }200        hir::CallableKind::TupleStruct(strukt) => {201            res.doc = strukt.docs(db).map(Documentation::into_owned);202            format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition));203204            let generic_params = GenericDef::Adt(strukt.into())205                .params(db)206                .iter()207                .map(|param| param.display(db, display_target))208                .join(", ");209            if !generic_params.is_empty() {210                format_to!(res.signature, "<{}>", generic_params);211            }212        }213        hir::CallableKind::TupleEnumVariant(variant) => {214            res.doc = variant.docs(db).map(Documentation::into_owned);215            format_to!(216                res.signature,217                "enum {}",218                variant.parent_enum(db).name(db).display(db, edition),219            );220221            let generic_params = GenericDef::Adt(variant.parent_enum(db).into())222                .params(db)223                .iter()224                .map(|param| param.display(db, display_target))225                .join(", ");226            if !generic_params.is_empty() {227                format_to!(res.signature, "<{}>", generic_params);228            }229230            format_to!(res.signature, "::{}", variant.name(db).display(db, edition))231        }232        hir::CallableKind::Closure(closure) => {233            let fn_trait = closure.fn_trait(db);234            format_to!(res.signature, "impl {fn_trait}")235        }236        hir::CallableKind::FnPtr => format_to!(res.signature, "fn"),237        hir::CallableKind::FnImpl(fn_trait) => match callable.ty().as_adt() {238            // FIXME: Render docs of the concrete trait impl function239            Some(adt) => format_to!(240                res.signature,241                "<{} as {fn_trait}>::{}",242                adt.name(db).display(db, edition),243                fn_trait.function_name()244            ),245            None => format_to!(res.signature, "impl {fn_trait}"),246        },247    }248249    res.signature.push('(');250    {251        if let Some((self_param, _)) = callable.receiver_param(db) {252            format_to!(res.signature, "{}", self_param.display(db, display_target))253        }254        let mut buf = String::new();255        for (idx, p) in callable.params().into_iter().enumerate() {256            buf.clear();257            if let Some(param) = sema.source(p.clone()) {258                match param.value {259                    Either::Right(param) => match param.pat() {260                        Some(pat) => format_to!(buf, "{}: ", pat),261                        None => format_to!(buf, "?: "),262                    },263                    Either::Left(_) => format_to!(buf, "self: "),264                }265            }266            // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is267            // in the middle of entering call arguments.268            // In that case, fall back to render definitions of the respective parameters.269            // This is overly conservative: we do not substitute known type vars270            // (see FIXME in tests::impl_trait) and falling back on any unknowns.271            match (p.ty().contains_unknown(), fn_params.as_deref()) {272                (true, Some(fn_params)) => {273                    format_to!(buf, "{}", fn_params[idx].ty().display(db, display_target))274                }275                _ => format_to!(buf, "{}", p.ty().display(db, display_target)),276            }277            res.push_call_param(&buf);278        }279    }280    res.signature.push(')');281282    let mut render = |ret_type: hir::Type<'_>| {283        if !ret_type.is_unit() {284            format_to!(res.signature, " -> {}", ret_type.display(db, display_target));285        }286    };287    match callable.kind() {288        hir::CallableKind::Function(func) => render(func.async_ret_type(db).unwrap_or_else(|| {289            if callable.return_type().contains_unknown() {290                func.ret_type(db)291            } else {292                callable.return_type()293            }294        })),295        hir::CallableKind::Closure(_) | hir::CallableKind::FnPtr | hir::CallableKind::FnImpl(_) => {296            render(callable.return_type())297        }298        hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}299    }300    Some(res)301}302303fn signature_help_for_generics(304    sema: &Semantics<'_, RootDatabase>,305    arg_list: ast::GenericArgList,306    token: SyntaxToken,307    edition: Edition,308    display_target: DisplayTarget,309) -> Option<SignatureHelp> {310    let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) =311        generic_def_for_node(sema, &arg_list, &token)?;312    let mut res = SignatureHelp {313        doc: None,314        signature: String::new(),315        parameters: vec![],316        active_parameter: None,317    };318319    let db = sema.db;320    match generics_def {321        hir::GenericDef::Function(it) => {322            res.doc = it.docs(db).map(Documentation::into_owned);323            format_to!(res.signature, "fn {}", it.name(db).display(db, edition));324        }325        hir::GenericDef::Adt(hir::Adt::Enum(it)) => {326            res.doc = it.docs(db).map(Documentation::into_owned);327            format_to!(res.signature, "enum {}", it.name(db).display(db, edition));328            if let Some(variant) = variant {329                // In paths, generics of an enum can be specified *after* one of its variants.330                // eg. `None::<u8>`331                // We'll use the signature of the enum, but include the docs of the variant.332                res.doc = variant.docs(db).map(Documentation::into_owned);333            }334        }335        hir::GenericDef::Adt(hir::Adt::Struct(it)) => {336            res.doc = it.docs(db).map(Documentation::into_owned);337            format_to!(res.signature, "struct {}", it.name(db).display(db, edition));338        }339        hir::GenericDef::Adt(hir::Adt::Union(it)) => {340            res.doc = it.docs(db).map(Documentation::into_owned);341            format_to!(res.signature, "union {}", it.name(db).display(db, edition));342        }343        hir::GenericDef::Trait(it) => {344            res.doc = it.docs(db).map(Documentation::into_owned);345            format_to!(res.signature, "trait {}", it.name(db).display(db, edition));346        }347        hir::GenericDef::TypeAlias(it) => {348            res.doc = it.docs(db).map(Documentation::into_owned);349            format_to!(res.signature, "type {}", it.name(db).display(db, edition));350        }351        // These don't have generic args that can be specified352        hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) | hir::GenericDef::Static(_) => {353            return None;354        }355    }356357    let params = generics_def.params(sema.db);358    let num_lifetime_params =359        params.iter().take_while(|param| matches!(param, GenericParam::LifetimeParam(_))).count();360    if first_arg_is_non_lifetime {361        // Lifetime parameters were omitted.362        active_parameter += num_lifetime_params;363    }364    res.active_parameter = Some(active_parameter);365366    res.signature.push('<');367    let mut buf = String::new();368    for param in params {369        if let hir::GenericParam::TypeParam(ty) = param370            && ty.is_implicit(db)371        {372            continue;373        }374375        buf.clear();376        format_to!(buf, "{}", param.display(db, display_target));377        match param {378            GenericParam::TypeParam(param) => {379                if let Some(ty) = param.default(db) {380                    format_to!(buf, " = {}", ty.display(db, display_target));381                }382            }383            GenericParam::ConstParam(param) => {384                if let Some(expr) = param.default(db, display_target).and_then(|konst| konst.expr())385                {386                    format_to!(buf, " = {}", expr);387                }388            }389            _ => {}390        }391        res.push_generic_param(&buf);392    }393    if let hir::GenericDef::Trait(tr) = generics_def {394        add_assoc_type_bindings(db, &mut res, tr, arg_list, edition);395    }396    res.signature.push('>');397398    Some(res)399}400401fn add_assoc_type_bindings(402    db: &RootDatabase,403    res: &mut SignatureHelp,404    tr: Trait,405    args: ast::GenericArgList,406    edition: Edition,407) {408    if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() {409        // Assoc type bindings are only valid in type bound position.410        return;411    }412413    let present_bindings = args414        .generic_args()415        .filter_map(|arg| match arg {416            ast::GenericArg::AssocTypeArg(arg) => arg.name_ref().map(|n| n.to_string()),417            _ => None,418        })419        .collect::<BTreeSet<_>>();420421    let mut buf = String::new();422    for binding in &present_bindings {423        buf.clear();424        format_to!(buf, "{} = …", binding);425        res.push_generic_param(&buf);426    }427428    for item in tr.items_with_supertraits(db) {429        if let AssocItem::TypeAlias(ty) = item {430            let name = ty.name(db).display_no_db(edition).to_smolstr();431            if !present_bindings.contains(&*name) {432                buf.clear();433                format_to!(buf, "{} = …", name);434                res.push_generic_param(&buf);435            }436        }437    }438}439440fn signature_help_for_record_lit(441    sema: &Semantics<'_, RootDatabase>,442    record: ast::RecordExpr,443    token: SyntaxToken,444    edition: Edition,445    display_target: DisplayTarget,446) -> Option<SignatureHelp> {447    signature_help_for_record_(448        sema,449        record.record_expr_field_list()?.syntax().children_with_tokens(),450        &record.path()?,451        record452            .record_expr_field_list()?453            .fields()454            .filter_map(|field| sema.resolve_record_field(&field))455            .map(|(field, _, ty)| (field, ty)),456        token,457        edition,458        display_target,459    )460}461462fn signature_help_for_record_pat(463    sema: &Semantics<'_, RootDatabase>,464    record: ast::RecordPat,465    token: SyntaxToken,466    edition: Edition,467    display_target: DisplayTarget,468) -> Option<SignatureHelp> {469    signature_help_for_record_(470        sema,471        record.record_pat_field_list()?.syntax().children_with_tokens(),472        &record.path()?,473        record474            .record_pat_field_list()?475            .fields()476            .filter_map(|field| sema.resolve_record_pat_field(&field)),477        token,478        edition,479        display_target,480    )481}482483fn signature_help_for_tuple_struct_pat(484    sema: &Semantics<'_, RootDatabase>,485    pat: ast::TupleStructPat,486    token: SyntaxToken,487    edition: Edition,488    display_target: DisplayTarget,489) -> Option<SignatureHelp> {490    let path = pat.path()?;491    let path_res = sema.resolve_path(&path)?;492    let mut res = SignatureHelp {493        doc: None,494        signature: String::new(),495        parameters: vec![],496        active_parameter: None,497    };498    let db = sema.db;499500    let fields: Vec<_> = if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res {501        let en = variant.parent_enum(db);502503        res.doc = en.docs(db).map(Documentation::into_owned);504        format_to!(505            res.signature,506            "enum {}::{} (",507            en.name(db).display(db, edition),508            variant.name(db).display(db, edition)509        );510        variant.fields(db)511    } else {512        let adt = match path_res {513            PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?,514            PathResolution::Def(ModuleDef::Adt(adt)) => adt,515            _ => return None,516        };517518        match adt {519            hir::Adt::Struct(it) => {520                res.doc = it.docs(db).map(Documentation::into_owned);521                format_to!(res.signature, "struct {} (", it.name(db).display(db, edition));522                it.fields(db)523            }524            _ => return None,525        }526    };527    Some(signature_help_for_tuple_pat_ish(528        db,529        res,530        pat.syntax(),531        token,532        pat.fields(),533        fields.into_iter().map(|it| it.ty(db).to_type(db)),534        display_target,535    ))536}537538fn signature_help_for_tuple_pat(539    sema: &Semantics<'_, RootDatabase>,540    pat: ast::TuplePat,541    token: SyntaxToken,542    display_target: DisplayTarget,543) -> Option<SignatureHelp> {544    let db = sema.db;545    let field_pats = pat.fields();546    let pat = pat.into();547    let ty = sema.type_of_pat(&pat)?;548    let fields = ty.original.tuple_fields(db);549550    Some(signature_help_for_tuple_pat_ish(551        db,552        SignatureHelp {553            doc: None,554            signature: String::from('('),555            parameters: vec![],556            active_parameter: None,557        },558        pat.syntax(),559        token,560        field_pats,561        fields.into_iter(),562        display_target,563    ))564}565566fn signature_help_for_tuple_expr(567    sema: &Semantics<'_, RootDatabase>,568    expr: ast::TupleExpr,569    token: SyntaxToken,570    display_target: DisplayTarget,571) -> Option<SignatureHelp> {572    let active_parameter = Some(573        expr.syntax()574            .children_with_tokens()575            .filter_map(NodeOrToken::into_token)576            .filter(|t| t.kind() == T![,])577            .take_while(|t| t.text_range().start() <= token.text_range().start())578            .count(),579    );580581    let db = sema.db;582    let mut res = SignatureHelp {583        doc: None,584        signature: String::from('('),585        parameters: vec![],586        active_parameter,587    };588    let expr = sema.type_of_expr(&expr.into())?;589    let fields = expr.original.tuple_fields(db);590    let mut buf = String::new();591    for ty in fields {592        format_to!(buf, "{}", ty.display_truncated(db, Some(20), display_target));593        res.push_call_param(&buf);594        buf.clear();595    }596    res.signature.push(')');597    Some(res)598}599600fn signature_help_for_record_<'db>(601    sema: &Semantics<'db, RootDatabase>,602    field_list_children: SyntaxElementChildren,603    path: &ast::Path,604    fields2: impl Iterator<Item = (hir::Field, hir::Type<'db>)>,605    token: SyntaxToken,606    edition: Edition,607    display_target: DisplayTarget,608) -> Option<SignatureHelp> {609    let active_parameter = field_list_children610        .filter_map(NodeOrToken::into_token)611        .filter(|t| t.kind() == T![,])612        .take_while(|t| t.text_range().start() <= token.text_range().start())613        .count();614615    let mut res = SignatureHelp {616        doc: None,617        signature: String::new(),618        parameters: vec![],619        active_parameter: Some(active_parameter),620    };621622    let fields;623624    let db = sema.db;625    let path_res = sema.resolve_path(path)?;626    if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res {627        fields = variant.fields(db);628        let en = variant.parent_enum(db);629630        res.doc = en.docs(db).map(Documentation::into_owned);631        format_to!(632            res.signature,633            "enum {}::{} {{ ",634            en.name(db).display(db, edition),635            variant.name(db).display(db, edition)636        );637    } else {638        let adt = match path_res {639            PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?,640            PathResolution::Def(ModuleDef::Adt(adt)) => adt,641            _ => return None,642        };643644        match adt {645            hir::Adt::Struct(it) => {646                fields = it.fields(db);647                res.doc = it.docs(db).map(Documentation::into_owned);648                format_to!(res.signature, "struct {} {{ ", it.name(db).display(db, edition));649            }650            hir::Adt::Union(it) => {651                fields = it.fields(db);652                res.doc = it.docs(db).map(Documentation::into_owned);653                format_to!(res.signature, "union {} {{ ", it.name(db).display(db, edition));654            }655            _ => return None,656        }657    }658659    let mut fields =660        fields.into_iter().map(|field| (field.name(db), Some(field))).collect::<FxIndexMap<_, _>>();661    let mut buf = String::new();662    for (field, ty) in fields2 {663        let name = field.name(db);664        format_to!(665            buf,666            "{}: {}",667            name.display(db, edition),668            ty.display_truncated(db, Some(20), display_target)669        );670        res.push_record_field(&buf);671        buf.clear();672673        if let Some(field) = fields.get_mut(&name) {674            *field = None;675        }676    }677    for (name, field) in fields {678        let Some(field) = field else { continue };679        format_to!(680            buf,681            "{}: {}",682            name.display(db, edition),683            field.ty(db).display_truncated(db, Some(20), display_target)684        );685        res.push_record_field(&buf);686        buf.clear();687    }688    res.signature.push_str(" }");689    Some(res)690}691692fn signature_help_for_tuple_pat_ish<'db>(693    db: &'db RootDatabase,694    mut res: SignatureHelp,695    pat: &SyntaxNode,696    token: SyntaxToken,697    mut field_pats: AstChildren<ast::Pat>,698    fields: impl ExactSizeIterator<Item = hir::Type<'db>>,699    display_target: DisplayTarget,700) -> SignatureHelp {701    let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));702    let is_left_of_rest_pat =703        rest_pat.is_none_or(|it| token.text_range().start() < it.syntax().text_range().end());704705    let commas = pat706        .children_with_tokens()707        .filter_map(NodeOrToken::into_token)708        .filter(|t| t.kind() == T![,]);709710    res.active_parameter = {711        Some(if is_left_of_rest_pat {712            commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count()713        } else {714            let n_commas = commas715                .collect::<Vec<_>>()716                .into_iter()717                .rev()718                .take_while(|t| t.text_range().start() > token.text_range().start())719                .count();720            fields.len().saturating_sub(1).saturating_sub(n_commas)721        })722    };723724    let mut buf = String::new();725    for ty in fields {726        format_to!(buf, "{}", ty.display_truncated(db, Some(20), display_target));727        res.push_call_param(&buf);728        buf.clear();729    }730    res.signature.push(')');731    res732}733#[cfg(test)]734mod tests {735736    use expect_test::{Expect, expect};737    use ide_db::FilePosition;738    use stdx::format_to;739    use test_fixture::ChangeFixture;740741    use crate::RootDatabase;742743    /// Creates analysis from a multi-file fixture, returns positions marked with $0.744    pub(crate) fn position(745        #[rust_analyzer::rust_fixture] ra_fixture: &str,746    ) -> (RootDatabase, FilePosition) {747        let mut database = RootDatabase::default();748        let change_fixture = ChangeFixture::parse(ra_fixture);749        database.apply_change(change_fixture.change);750        let (file_id, range_or_offset) =751            change_fixture.file_position.expect("expected a marker ($0)");752        let offset = range_or_offset.expect_offset();753        let position = FilePosition { file_id: file_id.file_id(), offset };754        (database, position)755    }756757    #[track_caller]758    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {759        let (db, position) = position(ra_fixture);760        let sig_help = hir::attach_db(&db, || crate::signature_help::signature_help(&db, position));761        let actual = match sig_help {762            Some(sig_help) => {763                let mut rendered = String::new();764                if let Some(docs) = &sig_help.doc {765                    format_to!(rendered, "{}\n------\n", docs.as_str());766                }767                format_to!(rendered, "{}\n", sig_help.signature);768                let mut offset = 0;769                for (i, range) in sig_help.parameter_ranges().iter().enumerate() {770                    let is_active = sig_help.active_parameter == Some(i);771772                    let start = u32::from(range.start());773                    let gap = start.checked_sub(offset).unwrap_or_else(|| {774                        panic!("parameter ranges out of order: {:?}", sig_help.parameter_ranges())775                    });776                    rendered.extend(std::iter::repeat_n(' ', gap as usize));777                    let param_text = &sig_help.signature[*range];778                    let width = param_text.chars().count(); // …779                    let marker = if is_active { '^' } else { '-' };780                    rendered.extend(std::iter::repeat_n(marker, width));781                    offset += gap + u32::from(range.len());782                }783                if !sig_help.parameter_ranges().is_empty() {784                    format_to!(rendered, "\n");785                }786                rendered787            }788            None => String::new(),789        };790        expect.assert_eq(&actual);791    }792793    #[test]794    fn test_fn_signature_two_args() {795        check(796            r#"797//- minicore: sized, fn798fn foo(x: u32, y: u32) -> u32 {x + y}799fn bar() { foo($03, ); }800"#,801            expect![[r#"802                fn foo(x: u32, y: u32) -> u32803                       ^^^^^^  ------804            "#]],805        );806        check(807            r#"808//- minicore: sized, fn809fn foo(x: u32, y: u32) -> u32 {x + y}810fn bar() { foo(3$0, ); }811"#,812            expect![[r#"813                fn foo(x: u32, y: u32) -> u32814                       ^^^^^^  ------815            "#]],816        );817        check(818            r#"819//- minicore: sized, fn820fn foo(x: u32, y: u32) -> u32 {x + y}821fn bar() { foo(3,$0 ); }822"#,823            expect![[r#"824                fn foo(x: u32, y: u32) -> u32825                       ------  ^^^^^^826            "#]],827        );828        check(829            r#"830//- minicore: sized, fn831fn foo(x: u32, y: u32) -> u32 {x + y}832fn bar() { foo(3, $0); }833"#,834            expect![[r#"835                fn foo(x: u32, y: u32) -> u32836                       ------  ^^^^^^837            "#]],838        );839    }840841    #[test]842    fn test_fn_signature_two_args_empty() {843        check(844            r#"845//- minicore: sized, fn846fn foo(x: u32, y: u32) -> u32 {x + y}847fn bar() { foo($0); }848"#,849            expect![[r#"850                fn foo(x: u32, y: u32) -> u32851                       ^^^^^^  ------852            "#]],853        );854    }855856    #[test]857    fn test_fn_signature_two_args_first_generics() {858        check(859            r#"860//- minicore: sized, fn861fn foo<T, U: Copy + Display>(x: T, y: U) -> u32862    where T: Copy + Display, U: Debug863{ x + y }864865fn bar() { foo($03, ); }866"#,867            expect![[r#"868                fn foo<T, U>(x: i32, y: U) -> u32869                             ^^^^^^  ----870            "#]],871        );872    }873874    #[test]875    fn test_fn_signature_no_params() {876        check(877            r#"878//- minicore: sized, fn879fn foo<T>() -> T where T: Copy + Display {}880fn bar() { foo($0); }881"#,882            expect![[r#"883                fn foo<T>() -> T884            "#]],885        );886    }887888    #[test]889    fn test_fn_signature_for_impl() {890        check(891            r#"892//- minicore: sized, fn893struct F;894impl F { pub fn new() { } }895fn bar() {896    let _ : F = F::new($0);897}898"#,899            expect![[r#"900                fn new()901            "#]],902        );903    }904905    #[test]906    fn test_fn_signature_for_method_self() {907        check(908            r#"909//- minicore: sized, fn910struct S;911impl S { pub fn do_it(&self) {} }912913fn bar() {914    let s: S = S;915    s.do_it($0);916}917"#,918            expect![[r#"919                fn do_it(&self)920            "#]],921        );922    }923924    #[test]925    fn test_fn_signature_for_method_with_arg() {926        check(927            r#"928//- minicore: sized, fn929struct S;930impl S {931    fn foo(&self, x: i32) {}932}933934fn main() { S.foo($0); }935"#,936            expect![[r#"937                fn foo(&self, x: i32)938                              ^^^^^^939            "#]],940        );941    }942943    #[test]944    fn test_fn_signature_for_generic_method() {945        check(946            r#"947//- minicore: sized, fn948struct S<T>(T);949impl<T> S<T> {950    fn foo(&self, x: T) {}951}952953fn main() { S(1u32).foo($0); }954"#,955            expect![[r#"956                fn foo(&self, x: u32)957                              ^^^^^^958            "#]],959        );960    }961962    #[test]963    fn test_fn_signature_for_method_with_arg_as_assoc_fn() {964        check(965            r#"966//- minicore: sized, fn967struct S;968impl S {969    fn foo(&self, x: i32) {}970}971972fn main() { S::foo($0); }973"#,974            expect![[r#"975                fn foo(self: &S, x: i32)976                       ^^^^^^^^  ------977            "#]],978        );979    }980981    #[test]982    fn test_fn_signature_with_docs_simple() {983        check(984            r#"985//- minicore: sized, fn986/// test987// non-doc-comment988fn foo(j: u32) -> u32 {989    j990}991992fn bar() {993    let _ = foo($0);994}995"#,996            expect![[r#"997                test998                ------999                fn foo(j: u32) -> u321000                       ^^^^^^1001            "#]],1002        );1003    }10041005    #[test]1006    fn test_fn_signature_with_docs() {1007        check(1008            r#"1009//- minicore: sized, fn1010/// Adds one to the number given.1011///1012/// # Examples1013///1014/// ```1015/// let five = 5;1016///1017/// assert_eq!(6, my_crate::add_one(5));1018/// ```1019pub fn add_one(x: i32) -> i32 {1020    x + 11021}10221023pub fn r#do() {1024    add_one($01025}"#,1026            expect![[r##"1027                Adds one to the number given.10281029                # Examples10301031                ```1032                let five = 5;10331034                assert_eq!(6, my_crate::add_one(5));1035                ```1036                ------1037                fn add_one(x: i32) -> i321038                           ^^^^^^1039            "##]],1040        );1041    }10421043    #[test]1044    fn test_fn_signature_with_docs_impl() {1045        check(1046            r#"1047//- minicore: sized, fn1048struct addr;1049impl addr {1050    /// Adds one to the number given.1051    ///1052    /// # Examples1053    ///1054    /// ```1055    /// let five = 5;1056    ///1057    /// assert_eq!(6, my_crate::add_one(5));1058    /// ```1059    pub fn add_one(x: i32) -> i32 {1060        x + 11061    }1062}10631064pub fn do_it() {1065    addr {};1066    addr::add_one($0);1067}1068"#,1069            expect![[r##"1070                Adds one to the number given.10711072                # Examples10731074                ```1075                let five = 5;10761077                assert_eq!(6, my_crate::add_one(5));1078                ```1079                ------1080                fn add_one(x: i32) -> i321081                           ^^^^^^1082            "##]],1083        );1084    }10851086    #[test]1087    fn test_fn_signature_with_docs_from_actix() {1088        check(1089            r#"1090//- minicore: sized, fn1091trait Actor {1092    /// Actor execution context type1093    type Context;1094}1095trait WriteHandler<E>1096where1097    Self: Actor1098{1099    /// Method is called when writer finishes.1100    ///1101    /// By default this method stops actor's `Context`.1102    fn finished(&mut self, ctx: &mut Self::Context) {}1103}11041105fn foo(mut r: impl WriteHandler<()>) {1106    r.finished($0);1107}1108"#,1109            expect![[r#"1110                Method is called when writer finishes.11111112                By default this method stops actor's `Context`.1113                ------1114                fn finished(&mut self, ctx: &mut <impl WriteHandler<()> as Actor>::Context)1115                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1116            "#]],1117        );1118    }11191120    #[test]1121    fn call_info_bad_offset() {1122        check(1123            r#"1124//- minicore: sized, fn1125fn foo(x: u32, y: u32) -> u32 {x + y}1126fn bar() { foo $0 (3, ); }1127"#,1128            expect![[""]],1129        );1130    }11311132    #[test]1133    fn outside_of_arg_list() {1134        check(1135            r#"1136//- minicore: sized, fn1137fn foo(a: u8) {}1138fn f() {1139    foo(123)$01140}1141"#,1142            expect![[]],1143        );1144        check(1145            r#"1146//- minicore: sized, fn1147fn foo<T>(a: u8) {}1148fn f() {1149    foo::<u32>$0()1150}1151"#,1152            expect![[]],1153        );1154        check(1155            r#"1156//- minicore: sized, fn1157fn foo(a: u8) -> u8 {a}1158fn bar(a: u8) -> u8 {a}1159fn f() {1160    foo(bar(123)$0)1161}1162"#,1163            expect![[r#"1164                fn foo(a: u8) -> u81165                       ^^^^^1166            "#]],1167        );1168        check(1169            r#"1170//- minicore: sized, fn1171struct Vec<T>(T);1172struct Vec2<T>(T);1173fn f() {1174    let _: Vec2<Vec<u8>$0>1175}1176"#,1177            expect![[r#"1178                struct Vec2<T>1179                            ^1180            "#]],1181        );1182    }11831184    #[test]1185    fn test_nested_method_in_lambda() {1186        check(1187            r#"1188//- minicore: sized, fn1189struct Foo;1190impl Foo { fn bar(&self, _: u32) { } }11911192fn bar(_: u32) { }11931194fn main() {1195    let foo = Foo;1196    std::thread::spawn(move || foo.bar($0));1197}1198"#,1199            expect![[r#"1200                fn bar(&self, _: u32)1201                              ^^^^^^1202            "#]],1203        );1204    }12051206    #[test]1207    fn works_for_tuple_structs() {1208        check(1209            r#"1210//- minicore: sized, fn1211/// A cool tuple struct1212struct S(u32, i32);1213fn main() {1214    let s = S(0, $0);1215}1216"#,1217            expect![[r#"1218                A cool tuple struct1219                ------1220                struct S(u32, i32)1221                         ---  ^^^1222            "#]],1223        );1224    }12251226    #[test]1227    fn tuple_struct_pat() {1228        check(1229            r#"1230//- minicore: sized, fn1231/// A cool tuple struct1232struct S(u32, i32);1233fn main() {1234    let S(0, $0);1235}1236"#,1237            expect![[r#"1238                A cool tuple struct1239                ------1240                struct S (u32, i32)1241                          ---  ^^^1242            "#]],1243        );1244    }12451246    #[test]1247    fn tuple_struct_pat_rest() {1248        check(1249            r#"1250//- minicore: sized, fn1251/// A cool tuple struct1252struct S(u32, i32, f32, u16);1253fn main() {1254    let S(0, .., $0);1255}1256"#,1257            expect![[r#"1258                A cool tuple struct1259                ------1260                struct S (u32, i32, f32, u16)1261                          ---  ---  ---  ^^^1262            "#]],1263        );1264        check(1265            r#"1266//- minicore: sized, fn1267/// A cool tuple struct1268struct S(u32, i32, f32, u16, u8);1269fn main() {1270    let S(0, .., $0, 0);1271}1272"#,1273            expect![[r#"1274                A cool tuple struct1275                ------1276                struct S (u32, i32, f32, u16, u8)1277                          ---  ---  ---  ^^^  --1278            "#]],1279        );1280        check(1281            r#"1282//- minicore: sized, fn1283/// A cool tuple struct1284struct S(u32, i32, f32, u16);1285fn main() {1286    let S($0, .., 1);1287}1288"#,1289            expect![[r#"1290                A cool tuple struct1291                ------1292                struct S (u32, i32, f32, u16)1293                          ^^^  ---  ---  ---1294            "#]],1295        );1296        check(1297            r#"1298//- minicore: sized, fn1299/// A cool tuple struct1300struct S(u32, i32, f32, u16, u8);1301fn main() {1302    let S(1, .., 1, $0, 2);1303}1304"#,1305            expect![[r#"1306                A cool tuple struct1307                ------1308                struct S (u32, i32, f32, u16, u8)1309                          ---  ---  ---  ^^^  --1310            "#]],1311        );1312        check(1313            r#"1314//- minicore: sized, fn1315/// A cool tuple struct1316struct S(u32, i32, f32, u16);1317fn main() {1318    let S(1, $0.., 1);1319}1320"#,1321            expect![[r#"1322                A cool tuple struct1323                ------1324                struct S (u32, i32, f32, u16)1325                          ---  ^^^  ---  ---1326            "#]],1327        );1328        check(1329            r#"1330//- minicore: sized, fn1331/// A cool tuple struct1332struct S(u32, i32, f32, u16);1333fn main() {1334    let S(1, ..$0, 1);1335}1336"#,1337            expect![[r#"1338                A cool tuple struct1339                ------1340                struct S (u32, i32, f32, u16)1341                          ---  ^^^  ---  ---1342            "#]],1343        );1344    }13451346    #[test]1347    fn generic_struct() {1348        check(1349            r#"1350//- minicore: sized, fn1351struct S<T>(T);1352fn main() {1353    let s = S($0);1354}1355"#,1356            expect![[r#"1357                struct S<T>({unknown})1358                            ^^^^^^^^^1359            "#]],1360        );1361    }13621363    #[test]1364    fn works_for_enum_variants() {1365        check(1366            r#"1367//- minicore: sized, fn1368enum E {1369    /// A Variant1370    A(i32),1371    /// Another1372    B,1373    /// And C1374    C { a: i32, b: i32 }1375}13761377fn main() {1378    let a = E::A($0);1379}1380"#,1381            expect![[r#"1382                A Variant1383                ------1384                enum E::A(i32)1385                          ^^^1386            "#]],1387        );1388    }13891390    #[test]1391    fn cant_call_struct_record() {1392        check(1393            r#"1394//- minicore: sized, fn1395struct S { x: u32, y: i32 }1396fn main() {1397    let s = S($0);1398}1399"#,1400            expect![[""]],1401        );1402    }14031404    #[test]1405    fn cant_call_enum_record() {1406        check(1407            r#"1408//- minicore: sized, fn1409enum E {1410    /// A Variant1411    A(i32),1412    /// Another1413    B,1414    /// And C1415    C { a: i32, b: i32 }1416}14171418fn main() {1419    let a = E::C($0);1420}1421"#,1422            expect![[""]],1423        );1424    }14251426    #[test]1427    fn fn_signature_for_call_in_macro() {1428        check(1429            r#"1430//- minicore: sized, fn1431macro_rules! id { ($($tt:tt)*) => { $($tt)* } }1432fn foo() { }1433id! {1434    fn bar() { foo($0); }1435}1436"#,1437            expect![[r#"1438                fn foo()1439            "#]],1440        );1441    }14421443    #[test]1444    fn fn_signature_for_method_call_defined_in_macro() {1445        check(1446            r#"1447//- minicore: sized, fn1448macro_rules! id { ($($tt:tt)*) => { $($tt)* } }1449struct S;1450id! {1451    impl S {1452        fn foo<'a>(&'a mut self) {}1453    }1454}1455fn test() { S.foo($0); }1456"#,1457            expect![[r#"1458                fn foo<'a>(&'a mut self)1459            "#]],1460        );1461    }14621463    #[test]1464    fn call_info_for_lambdas() {1465        check(1466            r#"1467//- minicore: sized, fn1468struct S;1469fn foo(s: S) -> i32 { 92 }1470fn main() {1471    let _move = S;1472    (|s| {{_move}; foo(s)})($0)1473}1474        "#,1475            expect![[r#"1476                impl FnOnce(s: S) -> i321477                            ^^^^1478            "#]],1479        );1480        check(1481            r#"1482//- minicore: sized, fn1483struct S;1484fn foo(s: S) -> i32 { 92 }1485fn main() {1486    (|s| foo(s))($0)1487}1488        "#,1489            expect![[r#"1490                impl Fn(s: S) -> i321491                        ^^^^1492            "#]],1493        );1494        check(1495            r#"1496//- minicore: sized, fn1497struct S;1498fn foo(s: S) -> i32 { 92 }1499fn main() {1500    let mut mutate = 0;1501    (|s| { mutate = 1; foo(s) })($0)1502}1503        "#,1504            expect![[r#"1505                impl FnMut(s: S) -> i321506                           ^^^^1507            "#]],1508        );1509    }15101511    #[test]1512    fn call_info_for_fn_def_over_reference() {1513        check(1514            r#"1515//- minicore: sized, fn1516struct S;1517fn foo(s: S) -> i32 { 92 }1518fn main() {1519    let bar = &&&&&foo;1520    bar($0);1521}1522        "#,1523            expect![[r#"1524                fn foo(s: S) -> i321525                       ^^^^1526            "#]],1527        )1528    }15291530    #[test]1531    fn call_info_for_fn_ptr() {1532        check(1533            r#"1534//- minicore: sized, fn1535fn main(f: fn(i32, f64) -> char) {1536    f(0, $0)1537}1538        "#,1539            expect![[r#"1540                fn(i32, f64) -> char1541                   ---  ^^^1542            "#]],1543        )1544    }15451546    #[test]1547    fn call_info_for_fn_impl() {1548        check(1549            r#"1550//- minicore: sized, fn1551struct S;1552impl core::ops::FnOnce<(i32, f64)> for S {1553    type Output = char;1554}1555impl core::ops::FnMut<(i32, f64)> for S {}1556impl core::ops::Fn<(i32, f64)> for S {}1557fn main() {1558    S($0);1559}1560        "#,1561            expect![[r#"1562                <S as Fn>::call(i32, f64) -> char1563                                ^^^  ---1564            "#]],1565        );1566        check(1567            r#"1568//- minicore: sized, fn1569struct S;1570impl core::ops::FnOnce<(i32, f64)> for S {1571    type Output = char;1572}1573impl core::ops::FnMut<(i32, f64)> for S {}1574impl core::ops::Fn<(i32, f64)> for S {}1575fn main() {1576    S(1, $0);1577}1578        "#,1579            expect![[r#"1580                <S as Fn>::call(i32, f64) -> char1581                                ---  ^^^1582            "#]],1583        );1584        check(1585            r#"1586//- minicore: sized, fn1587struct S;1588impl core::ops::FnOnce<(i32, f64)> for S {1589    type Output = char;1590}1591impl core::ops::FnOnce<(char, char)> for S {1592    type Output = f64;1593}1594fn main() {1595    S($0);1596}1597        "#,1598            expect![""],1599        );1600        check(1601            r#"1602//- minicore: sized, fn1603struct S;1604impl core::ops::FnOnce<(i32, f64)> for S {1605    type Output = char;1606}1607impl core::ops::FnOnce<(char, char)> for S {1608    type Output = f64;1609}1610fn main() {1611    // FIXME: The ide layer loses the calling info here so we get an ambiguous trait solve result1612    S(0i32, $0);1613}1614        "#,1615            expect![""],1616        );1617    }16181619    #[test]1620    fn call_info_for_unclosed_call() {1621        check(1622            r#"1623//- minicore: sized, fn1624fn foo(foo: u32, bar: u32) {}1625fn main() {1626    foo($01627}"#,1628            expect![[r#"1629                fn foo(foo: u32, bar: u32)1630                       ^^^^^^^^  --------1631            "#]],1632        );1633        // check with surrounding space1634        check(1635            r#"1636//- minicore: sized, fn1637fn foo(foo: u32, bar: u32) {}1638fn main() {1639    foo( $01640}"#,1641            expect![[r#"1642                fn foo(foo: u32, bar: u32)1643                       ^^^^^^^^  --------1644            "#]],1645        )1646    }16471648    #[test]1649    fn test_multiline_argument() {1650        check(1651            r#"1652//- minicore: sized, fn1653fn callee(a: u8, b: u8) {}1654fn main() {1655    callee(match 0 {1656        0 => 1,$01657    })1658}"#,1659            expect![[r#""#]],1660        );1661        check(1662            r#"1663//- minicore: sized, fn1664fn callee(a: u8, b: u8) {}1665fn main() {1666    callee(match 0 {1667        0 => 1,1668    },$0)1669}"#,1670            expect![[r#"1671                fn callee(a: u8, b: u8)1672                          -----  ^^^^^1673            "#]],1674        );1675        check(1676            r#"1677//- minicore: sized, fn1678fn callee(a: u8, b: u8) {}1679fn main() {1680    callee($0match 0 {1681        0 => 1,1682    })1683}"#,1684            expect![[r#"1685                fn callee(a: u8, b: u8)1686                          ^^^^^  -----1687            "#]],1688        );1689    }16901691    #[test]1692    fn test_generics_simple() {1693        check(1694            r#"1695//- minicore: sized, fn1696/// Option docs.1697enum Option<T> {1698    Some(T),1699    None,1700}17011702fn f() {1703    let opt: Option<$01704}1705        "#,1706            expect![[r#"1707                Option docs.1708                ------1709                enum Option<T>1710                            ^1711            "#]],1712        );1713    }17141715    #[test]1716    fn test_generics_on_variant() {1717        check(1718            r#"1719//- minicore: sized, fn1720/// Option docs.1721enum Option<T> {1722    /// Some docs.1723    Some(T),1724    /// None docs.1725    None,1726}17271728use Option::*;17291730fn f() {1731    None::<$01732}1733        "#,1734            expect![[r#"1735                None docs.1736                ------1737                enum Option<T>1738                            ^1739            "#]],1740        );1741    }17421743    #[test]1744    fn test_lots_of_generics() {1745        check(1746            r#"1747//- minicore: sized, fn1748trait Tr<T> {}17491750struct S<T>(T);17511752impl<T> S<T> {1753    fn f<G, H>(g: G, h: impl Tr<G>) where G: Tr<()> {}1754}17551756fn f() {1757    S::<u8>::f::<(), $01758}1759        "#,1760            expect![[r#"1761                fn f<G: Tr<()>, H>1762                     ---------  ^1763            "#]],1764        );1765    }17661767    #[test]1768    fn test_generics_in_trait_ufcs() {1769        check(1770            r#"1771//- minicore: sized, fn1772trait Tr {1773    fn f<T: Tr, U>() {}1774}17751776struct S;17771778impl Tr for S {}17791780fn f() {1781    <S as Tr>::f::<$01782}1783        "#,1784            expect![[r#"1785                fn f<T: Tr, U>1786                     ^^^^^  -1787            "#]],1788        );1789    }17901791    #[test]1792    fn test_generics_in_method_call() {1793        check(1794            r#"1795//- minicore: sized, fn1796struct S;17971798impl S {1799    fn f<T>(&self) {}1800}18011802fn f() {1803    S.f::<$01804}1805        "#,1806            expect![[r#"1807                fn f<T>1808                     ^1809            "#]],1810        );1811    }18121813    #[test]1814    fn test_generic_param_in_method_call() {1815        check(1816            r#"1817//- minicore: sized, fn1818struct Foo;1819impl Foo {1820    fn test<V>(&mut self, val: V) {}1821}1822fn sup() {1823    Foo.test($0)1824}1825"#,1826            expect![[r#"1827                fn test<V>(&mut self, val: V)1828                                      ^^^^^^1829            "#]],1830        );1831    }18321833    #[test]1834    fn test_generic_kinds() {1835        check(1836            r#"1837//- minicore: sized, fn1838fn callee<'a, const A: u8, T, const C: u8>() {}18391840fn f() {1841    callee::<'static, $01842}1843        "#,1844            expect![[r#"1845                fn callee<'a, const A: u8, T, const C: u8>1846                          --  ^^^^^^^^^^^  -  -----------1847            "#]],1848        );1849        check(1850            r#"1851//- minicore: sized, fn1852fn callee<'a, const A: u8, T, const C: u8>() {}18531854fn f() {1855    callee::<NON_LIFETIME$01856}1857        "#,1858            expect![[r#"1859                fn callee<'a, const A: u8, T, const C: u8>1860                          --  ^^^^^^^^^^^  -  -----------1861            "#]],1862        );1863    }18641865    #[test]1866    fn test_trait_assoc_types() {1867        check(1868            r#"1869//- minicore: sized, fn1870trait Trait<'a, T> {1871    type Assoc;1872}1873fn f() -> impl Trait<(), $01874            "#,1875            expect![[r#"1876                trait Trait<'a, T, Assoc = …>1877                            --  -  ^^^^^^^^^1878            "#]],1879        );1880        check(1881            r#"1882//- minicore: sized, fn1883trait Iterator {1884    type Item;1885}1886fn f() -> impl Iterator<$01887            "#,1888            expect![[r#"1889                trait Iterator<Item = …>1890                               ^^^^^^^^1891            "#]],1892        );1893        check(1894            r#"1895//- minicore: sized, fn1896trait Iterator {1897    type Item;1898}1899fn f() -> impl Iterator<Item = $01900            "#,1901            expect![[r#"1902                trait Iterator<Item = …>1903                               ^^^^^^^^1904            "#]],1905        );1906        check(1907            r#"1908//- minicore: sized, fn1909trait Tr {1910    type A;1911    type B;1912}1913fn f() -> impl Tr<$01914            "#,1915            expect![[r#"1916                trait Tr<A = …, B = …>1917                         ^^^^^  -----1918            "#]],1919        );1920        check(1921            r#"1922//- minicore: sized, fn1923trait Tr {1924    type A;1925    type B;1926}1927fn f() -> impl Tr<B$01928            "#,1929            expect![[r#"1930                trait Tr<A = …, B = …>1931                         ^^^^^  -----1932            "#]],1933        );1934        check(1935            r#"1936//- minicore: sized, fn1937trait Tr {1938    type A;1939    type B;1940}1941fn f() -> impl Tr<B = $01942            "#,1943            expect![[r#"1944                trait Tr<B = …, A = …>1945                         ^^^^^  -----1946            "#]],1947        );1948        check(1949            r#"1950//- minicore: sized, fn1951trait Tr {1952    type A;1953    type B;1954}1955fn f() -> impl Tr<B = (), $01956            "#,1957            expect![[r#"1958                trait Tr<B = …, A = …>1959                         -----  ^^^^^1960            "#]],1961        );1962    }19631964    #[test]1965    fn test_supertrait_assoc() {1966        check(1967            r#"1968//- minicore: sized, fn1969trait Super {1970    type SuperTy;1971}1972trait Sub: Super + Super {1973    type SubTy;1974}1975fn f() -> impl Sub<$01976            "#,1977            expect![[r#"1978                trait Sub<SubTy = …, SuperTy = …>1979                          ^^^^^^^^^  -----------1980            "#]],1981        );1982    }19831984    #[test]1985    fn no_assoc_types_outside_type_bounds() {1986        check(1987            r#"1988//- minicore: sized, fn1989trait Tr<T> {1990    type Assoc;1991}19921993impl Tr<$01994        "#,1995            expect![[r#"1996            trait Tr<T>1997                     ^1998        "#]],1999        );2000    }

Code quality findings 20

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
self.parameters.iter().map(move |&it| &self.signature[it])
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
format_to!(buf, "{}", fn_params[idx].ty().display(db, display_target))
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
change_fixture.file_position.expect("expected a marker ($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
let param_text = &sig_help.signature[*range];
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 _ = foo($0);
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
res.signature.push('(');
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
if let Some(param) = sema.source(p.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 (p.ty().contains_unknown(), fn_params.as_deref()) {
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
res.signature.push('<');
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
.filter_map(|arg| match arg {
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
ast::GenericArg::AssocTypeArg(arg) => arg.name_ref().map(|n| n.to_string()),
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 adt = match path_res {
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 adt {
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
res.signature.push(')');
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 adt = match path_res {
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 adt {
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
res.signature.push(')');
Info: Raw thread spawned using std::thread::spawn. Ensure the JoinHandle is managed (usually by calling .join()) to wait for completion and handle potential panics, unless intentionally detached.
info correctness thread-spawn-unjoined
std::thread::spawn(move || foo.bar($0));
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use Option::*;
Info: Raw thread spawned using std::thread::spawn. Ensure the JoinHandle is managed (usually by calling .join()) to wait for completion and handle potential panics, unless intentionally detached.
info correctness thread-spawn-unjoined
std::thread::spawn(move || { bar(A:$0) } );

Get this view in your editor

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