]> git.lizzy.rs Git - rust.git/commitdiff
Simplify function rendering, remove constructor structs
authorLukas Wirth <lukastw97@gmail.com>
Tue, 21 Dec 2021 13:51:06 +0000 (14:51 +0100)
committerLukas Wirth <lukastw97@gmail.com>
Tue, 21 Dec 2021 13:51:06 +0000 (14:51 +0100)
crates/ide_completion/src/completions.rs
crates/ide_completion/src/render.rs
crates/ide_completion/src/render/function.rs

index 53f5ad49921faf083502e4b3f5907b394adbf1e9..974264c319bd65cfbc6fb3ef92fedf7e1f0609a1 100644 (file)
@@ -115,7 +115,7 @@ pub(crate) fn add_function(
         if !ctx.is_visible(&func) {
             return;
         }
-        self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func));
+        self.add(render_fn(RenderContext::new(ctx), None, local_name, func));
     }
 
     pub(crate) fn add_method(
@@ -128,7 +128,7 @@ pub(crate) fn add_method(
         if !ctx.is_visible(&func) {
             return;
         }
-        self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
+        self.add(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
     }
 
     pub(crate) fn add_const(&mut self, ctx: &CompletionContext, konst: hir::Const) {
index f26fc3ec1fbaa20d79a258c42e3774bc3a19911b..25f46e729925d94064cc48e9a5d0bdd20b35b312 100644 (file)
@@ -156,17 +156,16 @@ fn render_resolution_(
     let _p = profile::span("render_resolution");
     use hir::ModuleDef::*;
 
+    let db = ctx.db();
+
     let kind = match resolution {
         ScopeDef::ModuleDef(Function(func)) => {
-            return render_fn(ctx, import_to_add, Some(local_name), func)
+            return Some(render_fn(ctx, import_to_add, Some(local_name), func));
         }
         ScopeDef::ModuleDef(Variant(var)) if ctx.completion.pattern_ctx.is_none() => {
-            return Some(render_variant(ctx, import_to_add, Some(local_name), var, None))
-        }
-        ScopeDef::MacroDef(mac) => {
-            let item = render_macro(ctx, import_to_add, local_name, mac);
-            return item;
+            return Some(render_variant(ctx, import_to_add, Some(local_name), var, None));
         }
+        ScopeDef::MacroDef(mac) => return render_macro(ctx, import_to_add, local_name, mac),
         ScopeDef::Unknown => {
             let mut item = CompletionItem::new(
                 CompletionItemKind::UnresolvedReference,
@@ -206,9 +205,9 @@ fn render_resolution_(
     let local_name = local_name.to_smol_str();
     let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
     if let ScopeDef::Local(local) = resolution {
-        let ty = local.ty(ctx.db());
+        let ty = local.ty(db);
         if !ty.is_unknown() {
-            item.detail(ty.display(ctx.db()).to_string());
+            item.detail(ty.display(db).to_string());
         }
 
         item.set_relevance(CompletionRelevance {
@@ -224,15 +223,15 @@ fn render_resolution_(
     };
 
     // Add `<>` for generic types
-    if matches!(
+    let type_path_no_ty_args = matches!(
         ctx.completion.path_context,
         Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
-    ) && ctx.completion.config.add_call_parenthesis
-    {
+    ) && ctx.completion.config.add_call_parenthesis;
+    if type_path_no_ty_args {
         if let Some(cap) = ctx.snippet_cap() {
             let has_non_default_type_params = match resolution {
-                ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
-                ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
+                ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(db),
+                ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(db),
                 _ => false,
             };
             if has_non_default_type_params {
@@ -243,7 +242,7 @@ fn render_resolution_(
             }
         }
     }
-    item.set_documentation(scope_def_docs(ctx.db(), resolution))
+    item.set_documentation(scope_def_docs(db, resolution))
         .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
 
     if let Some(import_to_add) = import_to_add {
index 918210f2f36869147ff80eaa8b76cd7c274a7bbd..f166b87ab631c1b0a50732258910d8ad52083608 100644 (file)
@@ -1,11 +1,12 @@
 //! Renderer for function calls.
 
-use hir::{AsAssocItem, HirDisplay};
+use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
 use ide_db::SymbolKind;
 use itertools::Itertools;
 use stdx::format_to;
 
 use crate::{
+    context::CompletionContext,
     item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit},
     render::{
         builder_ext::Params, compute_exact_name_match, compute_ref_match, compute_type_match,
     },
 };
 
+enum FuncType {
+    Function,
+    Method(Option<hir::Name>),
+}
+
 pub(crate) fn render_fn(
     ctx: RenderContext<'_>,
     import_to_add: Option<ImportEdit>,
     local_name: Option<hir::Name>,
-    fn_: hir::Function,
-) -> Option<CompletionItem> {
+    func: hir::Function,
+) -> CompletionItem {
     let _p = profile::span("render_fn");
-    Some(FunctionRender::new(ctx, None, local_name, fn_, false)?.render(import_to_add))
+    render(ctx, local_name, func, FuncType::Function, import_to_add)
 }
 
 pub(crate) fn render_method(
@@ -28,135 +34,120 @@ pub(crate) fn render_method(
     import_to_add: Option<ImportEdit>,
     receiver: Option<hir::Name>,
     local_name: Option<hir::Name>,
-    fn_: hir::Function,
-) -> Option<CompletionItem> {
+    func: hir::Function,
+) -> CompletionItem {
     let _p = profile::span("render_method");
-    Some(FunctionRender::new(ctx, receiver, local_name, fn_, true)?.render(import_to_add))
+    render(ctx, local_name, func, FuncType::Method(receiver), import_to_add)
 }
 
-#[derive(Debug)]
-struct FunctionRender<'a> {
-    ctx: RenderContext<'a>,
-    name: hir::Name,
-    receiver: Option<hir::Name>,
+fn render(
+    ctx @ RenderContext { completion }: RenderContext<'_>,
+    local_name: Option<hir::Name>,
     func: hir::Function,
-    is_method: bool,
-}
-
-impl<'a> FunctionRender<'a> {
-    fn new(
-        ctx: RenderContext<'a>,
-        receiver: Option<hir::Name>,
-        local_name: Option<hir::Name>,
-        fn_: hir::Function,
-        is_method: bool,
-    ) -> Option<FunctionRender<'a>> {
-        let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()));
-
-        Some(FunctionRender { ctx, name, receiver, func: fn_, is_method })
-    }
+    func_type: FuncType,
+    import_to_add: Option<ImportEdit>,
+) -> CompletionItem {
+    let db = completion.db;
 
-    fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
-        let params = self.params();
-        let call = match &self.receiver {
-            Some(receiver) => format!("{}.{}", receiver, &self.name),
-            None => self.name.to_string(),
-        };
-        let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone());
-        item.set_documentation(self.ctx.docs(self.func))
-            .set_deprecated(
-                self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
-            )
-            .detail(self.detail())
-            .add_call_parens(self.ctx.completion, call.clone(), params);
-
-        if import_to_add.is_none() {
-            let db = self.ctx.db();
-            if let Some(actm) = self.func.as_assoc_item(db) {
-                if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
-                    item.trait_name(trt.name(db).to_smol_str());
-                }
-            }
-        }
+    let name = local_name.unwrap_or_else(|| func.name(db));
+    let params = params(completion, func, &func_type);
 
-        if let Some(import_to_add) = import_to_add {
-            item.add_import(import_to_add);
-        }
-        item.lookup_by(self.name.to_smol_str());
-
-        let ret_type = self.func.ret_type(self.ctx.db());
-        item.set_relevance(CompletionRelevance {
-            type_match: compute_type_match(self.ctx.completion, &ret_type),
-            exact_name_match: compute_exact_name_match(self.ctx.completion, &call),
-            ..CompletionRelevance::default()
-        });
-
-        if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ret_type) {
-            // FIXME
-            // For now we don't properly calculate the edits for ref match
-            // completions on methods, so we've disabled them. See #8058.
-            if !self.is_method {
-                item.ref_match(ref_match);
+    // FIXME: SmolStr?
+    let call = match &func_type {
+        FuncType::Method(Some(receiver)) => format!("{}.{}", receiver, &name),
+        _ => name.to_string(),
+    };
+    let mut item = CompletionItem::new(
+        if func.self_param(db).is_some() {
+            CompletionItemKind::Method
+        } else {
+            CompletionItemKind::SymbolKind(SymbolKind::Function)
+        },
+        ctx.source_range(),
+        call.clone(),
+    );
+    item.set_documentation(ctx.docs(func))
+        .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
+        .detail(detail(db, func))
+        .add_call_parens(completion, call.clone(), params);
+
+    if import_to_add.is_none() {
+        if let Some(actm) = func.as_assoc_item(db) {
+            if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
+                item.trait_name(trt.name(db).to_smol_str());
             }
         }
-
-        item.build()
     }
 
-    fn detail(&self) -> String {
-        let ret_ty = self.func.ret_type(self.ctx.db());
-        let mut detail = format!("fn({})", self.params_display());
-        if !ret_ty.is_unit() {
-            format_to!(detail, " -> {}", ret_ty.display(self.ctx.db()));
+    if let Some(import_to_add) = import_to_add {
+        item.add_import(import_to_add);
+    }
+    item.lookup_by(name.to_smol_str());
+
+    let ret_type = func.ret_type(db);
+    item.set_relevance(CompletionRelevance {
+        type_match: compute_type_match(completion, &ret_type),
+        exact_name_match: compute_exact_name_match(completion, &call),
+        ..CompletionRelevance::default()
+    });
+
+    if let Some(ref_match) = compute_ref_match(completion, &ret_type) {
+        // FIXME
+        // For now we don't properly calculate the edits for ref match
+        // completions on methods, so we've disabled them. See #8058.
+        if matches!(func_type, FuncType::Function) {
+            item.ref_match(ref_match);
         }
-        detail
     }
 
-    fn params_display(&self) -> String {
-        if let Some(self_param) = self.func.self_param(self.ctx.db()) {
-            let params = self
-                .func
-                .assoc_fn_params(self.ctx.db())
-                .into_iter()
-                .skip(1) // skip the self param because we are manually handling that
-                .map(|p| p.ty().display(self.ctx.db()).to_string());
+    item.build()
+}
 
-            std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ")
-        } else {
-            let params = self
-                .func
-                .assoc_fn_params(self.ctx.db())
-                .into_iter()
-                .map(|p| p.ty().display(self.ctx.db()).to_string())
-                .join(", ");
-            params
-        }
+fn detail(db: &dyn HirDatabase, func: hir::Function) -> String {
+    let ret_ty = func.ret_type(db);
+    let mut detail = format!("fn({})", params_display(db, func));
+    if !ret_ty.is_unit() {
+        format_to!(detail, " -> {}", ret_ty.display(db));
     }
+    detail
+}
 
-    fn params(&self) -> Params {
-        let (params, self_param) =
-            if self.ctx.completion.has_dot_receiver() || self.receiver.is_some() {
-                (self.func.method_params(self.ctx.db()).unwrap_or_default(), None)
-            } else {
-                let self_param = self.func.self_param(self.ctx.db());
-
-                let mut assoc_params = self.func.assoc_fn_params(self.ctx.db());
-                if self_param.is_some() {
-                    assoc_params.remove(0);
-                }
-                (assoc_params, self_param)
-            };
-
-        Params::Named(self_param, params)
+fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String {
+    if let Some(self_param) = func.self_param(db) {
+        let assoc_fn_params = func.assoc_fn_params(db);
+        let params = assoc_fn_params
+            .iter()
+            .skip(1) // skip the self param because we are manually handling that
+            .map(|p| p.ty().display(db));
+        format!(
+            "{}{}",
+            self_param.display(db),
+            params.format_with("", |display, f| {
+                f(&", ")?;
+                f(&display)
+            })
+        )
+    } else {
+        let assoc_fn_params = func.assoc_fn_params(db);
+        assoc_fn_params.iter().map(|p| p.ty().display(db)).join(", ")
     }
+}
 
-    fn kind(&self) -> CompletionItemKind {
-        if self.func.self_param(self.ctx.db()).is_some() {
-            CompletionItemKind::Method
+fn params(ctx: &CompletionContext<'_>, func: hir::Function, func_type: &FuncType) -> Params {
+    let (params, self_param) =
+        if ctx.has_dot_receiver() || matches!(func_type, FuncType::Method(Some(_))) {
+            (func.method_params(ctx.db).unwrap_or_default(), None)
         } else {
-            SymbolKind::Function.into()
-        }
-    }
+            let self_param = func.self_param(ctx.db);
+
+            let mut assoc_params = func.assoc_fn_params(ctx.db);
+            if self_param.is_some() {
+                assoc_params.remove(0);
+            }
+            (assoc_params, self_param)
+        };
+
+    Params::Named(self_param, params)
 }
 
 #[cfg(test)]