aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model.rs76
-rw-r--r--crates/ra_hir/src/lib.rs13
-rw-r--r--crates/ra_hir/src/semantics.rs25
-rw-r--r--crates/ra_hir/src/source_analyzer.rs6
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs10
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs10
-rw-r--r--crates/ra_ide/src/call_info.rs332
-rw-r--r--crates/ra_ide/src/completion/presentation.rs7
-rw-r--r--crates/ra_ide/src/display/function_signature.rs21
-rw-r--r--crates/ra_ide/src/inlay_hints.rs10
-rw-r--r--crates/rust-analyzer/src/handlers.rs15
-rw-r--r--crates/rust-analyzer/src/to_proto.rs43
12 files changed, 310 insertions, 258 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 9891b0785..057dfb82a 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,5 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use std::sync::Arc; 2use std::{iter, sync::Arc};
3 3
4use arrayvec::ArrayVec; 4use arrayvec::ArrayVec;
5use either::Either; 5use either::Either;
@@ -12,6 +12,7 @@ use hir_def::{
12 import_map, 12 import_map,
13 per_ns::PerNs, 13 per_ns::PerNs,
14 resolver::{HasResolver, Resolver}, 14 resolver::{HasResolver, Resolver},
15 src::HasSource as _,
15 type_ref::{Mutability, TypeRef}, 16 type_ref::{Mutability, TypeRef},
16 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, 17 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
17 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, 18 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId,
@@ -25,8 +26,8 @@ use hir_expand::{
25use hir_ty::{ 26use hir_ty::{
26 autoderef, 27 autoderef,
27 display::{HirDisplayError, HirFormatter}, 28 display::{HirDisplayError, HirFormatter},
28 method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, 29 method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate,
29 TraitEnvironment, Ty, TyDefId, TypeCtor, 30 InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
30}; 31};
31use ra_db::{CrateId, Edition, FileId}; 32use ra_db::{CrateId, Edition, FileId};
32use ra_prof::profile; 33use ra_prof::profile;
@@ -40,7 +41,7 @@ use stdx::impl_from;
40use crate::{ 41use crate::{
41 db::{DefDatabase, HirDatabase}, 42 db::{DefDatabase, HirDatabase},
42 has_source::HasSource, 43 has_source::HasSource,
43 CallableDefId, HirDisplay, InFile, Name, 44 HirDisplay, InFile, Name,
44}; 45};
45 46
46/// hir::Crate describes a single crate. It's the main interface with which 47/// hir::Crate describes a single crate. It's the main interface with which
@@ -1168,6 +1169,12 @@ impl Type {
1168 Type::new(db, krate, def, ty) 1169 Type::new(db, krate, def, ty)
1169 } 1170 }
1170 1171
1172 pub fn is_unit(&self) -> bool {
1173 matches!(
1174 self.ty.value,
1175 Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { cardinality: 0 }, .. })
1176 )
1177 }
1171 pub fn is_bool(&self) -> bool { 1178 pub fn is_bool(&self) -> bool {
1172 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })) 1179 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }))
1173 } 1180 }
@@ -1225,9 +1232,10 @@ impl Type {
1225 db.trait_solve(self.krate, goal).is_some() 1232 db.trait_solve(self.krate, goal).is_some()
1226 } 1233 }
1227 1234
1228 // FIXME: this method is broken, as it doesn't take closures into account. 1235 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1229 pub fn as_callable(&self) -> Option<CallableDefId> { 1236 let (id, substs) = self.ty.value.as_callable()?;
1230 Some(self.ty.value.as_callable()?.0) 1237 let sig = db.callable_item_signature(id).subst(substs);
1238 Some(Callable { ty: self.clone(), sig, id, is_bound_method: false })
1231 } 1239 }
1232 1240
1233 pub fn is_closure(&self) -> bool { 1241 pub fn is_closure(&self) -> bool {
@@ -1512,6 +1520,60 @@ impl HirDisplay for Type {
1512 } 1520 }
1513} 1521}
1514 1522
1523// FIXME: closures
1524#[derive(Debug)]
1525pub struct Callable {
1526 ty: Type,
1527 sig: FnSig,
1528 id: CallableDefId,
1529 pub(crate) is_bound_method: bool,
1530}
1531
1532pub enum CallableKind {
1533 Function(Function),
1534 TupleStruct(Struct),
1535 TupleEnumVariant(EnumVariant),
1536}
1537
1538impl Callable {
1539 pub fn kind(&self) -> CallableKind {
1540 match self.id {
1541 CallableDefId::FunctionId(it) => CallableKind::Function(it.into()),
1542 CallableDefId::StructId(it) => CallableKind::TupleStruct(it.into()),
1543 CallableDefId::EnumVariantId(it) => CallableKind::TupleEnumVariant(it.into()),
1544 }
1545 }
1546 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
1547 let func = match self.id {
1548 CallableDefId::FunctionId(it) if self.is_bound_method => it,
1549 _ => return None,
1550 };
1551 let src = func.lookup(db.upcast()).source(db.upcast());
1552 let param_list = src.value.param_list()?;
1553 param_list.self_param()
1554 }
1555 pub fn params(&self, db: &dyn HirDatabase) -> Vec<(Option<ast::Pat>, Type)> {
1556 let types = self
1557 .sig
1558 .params()
1559 .iter()
1560 .skip(if self.is_bound_method { 1 } else { 0 })
1561 .map(|ty| self.ty.derived(ty.clone()));
1562 let patterns = match self.id {
1563 CallableDefId::FunctionId(func) => {
1564 let src = func.lookup(db.upcast()).source(db.upcast());
1565 src.value.param_list().map(|it| it.params().map(|it| it.pat()))
1566 }
1567 CallableDefId::StructId(_) => None,
1568 CallableDefId::EnumVariantId(_) => None,
1569 };
1570 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
1571 }
1572 pub fn return_type(&self) -> Type {
1573 self.ty.derived(self.sig.ret().clone())
1574 }
1575}
1576
1515/// For IDE only 1577/// For IDE only
1516#[derive(Debug)] 1578#[derive(Debug)]
1517pub enum ScopeDef { 1579pub enum ScopeDef {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index cf7134923..31f3241c9 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -32,10 +32,10 @@ mod has_source;
32 32
33pub use crate::{ 33pub use crate::{
34 code_model::{ 34 code_model::{
35 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, 35 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const,
36 DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, 36 Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
37 HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, 37 GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
38 Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, 38 Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
39 }, 39 },
40 has_source::HasSource, 40 has_source::HasSource,
41 semantics::{original_range, PathResolution, Semantics, SemanticsScope}, 41 semantics::{original_range, PathResolution, Semantics, SemanticsScope},
@@ -52,7 +52,8 @@ pub use hir_def::{
52 type_ref::Mutability, 52 type_ref::Mutability,
53}; 53};
54pub use hir_expand::{ 54pub use hir_expand::{
55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, 55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc,
56 MacroDefId, /* FIXME */
56 MacroFile, Origin, 57 MacroFile, Origin,
57}; 58};
58pub use hir_ty::{display::HirDisplay, CallableDefId}; 59pub use hir_ty::display::HirDisplay;
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 155b666d7..f5283ab22 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -6,7 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use hir_def::{ 7use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, TraitId, VariantId, 9 AsMacroCall, FunctionId, TraitId, VariantId,
10}; 10};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; 11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
@@ -24,8 +24,8 @@ use crate::{
24 diagnostics::Diagnostic, 24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, 27 AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module,
28 Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, 28 ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
29}; 29};
30use resolver::TypeNs; 30use resolver::TypeNs;
31 31
@@ -197,7 +197,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
197 } 197 }
198 198
199 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 199 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
200 self.imp.resolve_method_call(call) 200 self.imp.resolve_method_call(call).map(Function::from)
201 }
202
203 pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
204 self.imp.resolve_method_call_as_callable(call)
201 } 205 }
202 206
203 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { 207 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
@@ -385,10 +389,21 @@ impl<'db> SemanticsImpl<'db> {
385 self.analyze(param.syntax()).type_of_self(self.db, &param) 389 self.analyze(param.syntax()).type_of_self(self.db, &param)
386 } 390 }
387 391
388 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 392 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
389 self.analyze(call.syntax()).resolve_method_call(self.db, call) 393 self.analyze(call.syntax()).resolve_method_call(self.db, call)
390 } 394 }
391 395
396 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
397 // FIXME: this erases Substs
398 let func = self.resolve_method_call(call)?;
399 let ty = self.db.value_ty(func.into());
400 let resolver = self.analyze(call.syntax()).resolver;
401 let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?;
402 let mut res = ty.as_callable(self.db)?;
403 res.is_bound_method = true;
404 Some(res)
405 }
406
392 fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { 407 fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
393 self.analyze(field.syntax()).resolve_field(self.db, field) 408 self.analyze(field.syntax()).resolve_field(self.db, field)
394 } 409 }
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index ecb54f653..86a47a9e5 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -14,7 +14,7 @@ use hir_def::{
14 }, 14 },
15 expr::{ExprId, Pat, PatId}, 15 expr::{ExprId, Pat, PatId},
16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, 16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
17 AsMacroCall, DefWithBodyId, FieldId, LocalFieldId, VariantId, 17 AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, VariantId,
18}; 18};
19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
20use hir_ty::{ 20use hir_ty::{
@@ -142,9 +142,9 @@ impl SourceAnalyzer {
142 &self, 142 &self,
143 db: &dyn HirDatabase, 143 db: &dyn HirDatabase,
144 call: &ast::MethodCallExpr, 144 call: &ast::MethodCallExpr,
145 ) -> Option<Function> { 145 ) -> Option<FunctionId> {
146 let expr_id = self.expr_id(db, &call.clone().into())?; 146 let expr_id = self.expr_id(db, &call.clone().into())?;
147 self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) 147 self.infer.as_ref()?.method_resolution(expr_id)
148 } 148 }
149 149
150 pub(crate) fn resolve_field( 150 pub(crate) fn resolve_field(
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index 19692e70c..dbfa7fccb 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -226,7 +226,15 @@ impl CrateDefMap {
226 match enum_data.variant(&segment) { 226 match enum_data.variant(&segment) {
227 Some(local_id) => { 227 Some(local_id) => {
228 let variant = EnumVariantId { parent: e, local_id }; 228 let variant = EnumVariantId { parent: e, local_id };
229 PerNs::both(variant.into(), variant.into(), Visibility::Public) 229 match &*enum_data.variants[local_id].variant_data {
230 crate::adt::VariantData::Record(_) => {
231 PerNs::types(variant.into(), Visibility::Public)
232 }
233 crate::adt::VariantData::Tuple(_)
234 | crate::adt::VariantData::Unit => {
235 PerNs::both(variant.into(), variant.into(), Visibility::Public)
236 }
237 }
230 } 238 }
231 None => { 239 None => {
232 return ResolvePathResult::with( 240 return ResolvePathResult::with(
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index cb7e62cd6..6af251d23 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -95,9 +95,9 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
95 if let Some(func_target) = match &call_node { 95 if let Some(func_target) = match &call_node {
96 FnCallNode::CallExpr(expr) => { 96 FnCallNode::CallExpr(expr) => {
97 //FIXME: Type::as_callable is broken 97 //FIXME: Type::as_callable is broken
98 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 98 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?;
99 match callable_def { 99 match callable.kind() {
100 hir::CallableDefId::FunctionId(it) => { 100 hir::CallableKind::Function(it) => {
101 let fn_def: hir::Function = it.into(); 101 let fn_def: hir::Function = it.into();
102 let nav = fn_def.to_nav(db); 102 let nav = fn_def.to_nav(db);
103 Some(nav) 103 Some(nav)
@@ -109,10 +109,6 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio
109 let function = sema.resolve_method_call(&expr)?; 109 let function = sema.resolve_method_call(&expr)?;
110 Some(function.to_nav(db)) 110 Some(function.to_nav(db))
111 } 111 }
112 FnCallNode::MacroCallExpr(macro_call) => {
113 let macro_def = sema.resolve_macro_call(&macro_call)?;
114 Some(macro_def.to_nav(db))
115 }
116 } { 112 } {
117 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
118 } else { 114 } else {
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index 1fe1c21de..a2d23b2ec 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,20 +1,41 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use hir::Semantics; 2use hir::{Docs, HirDisplay, Semantics, Type};
3use ra_ide_db::RootDatabase; 3use ra_ide_db::RootDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, ArgListOwner}, 5 ast::{self, ArgListOwner},
6 match_ast, AstNode, SyntaxNode, SyntaxToken, 6 match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize,
7}; 7};
8use stdx::format_to;
8use test_utils::mark; 9use test_utils::mark;
9 10
10use crate::{FilePosition, FunctionSignature}; 11use crate::FilePosition;
11 12
12/// Contains information about a call site. Specifically the 13/// Contains information about a call site. Specifically the
13/// `FunctionSignature`and current parameter. 14/// `FunctionSignature`and current parameter.
14#[derive(Debug)] 15#[derive(Debug)]
15pub struct CallInfo { 16pub struct CallInfo {
16 pub signature: FunctionSignature, 17 pub doc: Option<String>,
18 pub signature: String,
17 pub active_parameter: Option<usize>, 19 pub active_parameter: Option<usize>,
20 parameters: Vec<TextRange>,
21}
22
23impl CallInfo {
24 pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
25 self.parameters.iter().map(move |&it| &self.signature[it])
26 }
27 pub fn parameter_ranges(&self) -> &[TextRange] {
28 &self.parameters
29 }
30 fn push_param(&mut self, param: &str) {
31 if !self.signature.ends_with('(') {
32 self.signature.push_str(", ");
33 }
34 let start = TextSize::of(&self.signature);
35 self.signature.push_str(param);
36 let end = TextSize::of(&self.signature);
37 self.parameters.push(TextRange::new(start, end))
38 }
18} 39}
19 40
20/// Computes parameter information for the given call expression. 41/// Computes parameter information for the given call expression.
@@ -24,105 +45,127 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
24 let file = file.syntax(); 45 let file = file.syntax();
25 let token = file.token_at_offset(position.offset).next()?; 46 let token = file.token_at_offset(position.offset).next()?;
26 let token = sema.descend_into_macros(token); 47 let token = sema.descend_into_macros(token);
27 call_info_for_token(&sema, token)
28}
29 48
30#[derive(Debug)] 49 let (callable, active_parameter) = call_info_impl(&sema, token)?;
31pub(crate) struct ActiveParameter {
32 /// FIXME: should be `Type` and `Name
33 pub(crate) ty: String,
34 pub(crate) name: String,
35}
36 50
37impl ActiveParameter { 51 let mut res =
38 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { 52 CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
39 call_info(db, position)?.into_active_parameter() 53
54 match callable.kind() {
55 hir::CallableKind::Function(func) => {
56 res.doc = func.docs(db).map(|it| it.as_str().to_string());
57 format_to!(res.signature, "fn {}", func.name(db));
58 }
59 hir::CallableKind::TupleStruct(strukt) => {
60 res.doc = strukt.docs(db).map(|it| it.as_str().to_string());
61 format_to!(res.signature, "struct {}", strukt.name(db));
62 }
63 hir::CallableKind::TupleEnumVariant(variant) => {
64 res.doc = variant.docs(db).map(|it| it.as_str().to_string());
65 format_to!(
66 res.signature,
67 "enum {}::{}",
68 variant.parent_enum(db).name(db),
69 variant.name(db)
70 );
71 }
40 } 72 }
41 73
42 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { 74 res.signature.push('(');
43 call_info_for_token(sema, token)?.into_active_parameter() 75 {
76 if let Some(self_param) = callable.receiver_param(db) {
77 format_to!(res.signature, "{}", self_param)
78 }
79 let mut buf = String::new();
80 for (pat, ty) in callable.params(db) {
81 buf.clear();
82 if let Some(pat) = pat {
83 format_to!(buf, "{}: ", pat);
84 }
85 format_to!(buf, "{}", ty.display(db));
86 res.push_param(&buf);
87 }
44 } 88 }
89 res.signature.push(')');
90
91 match callable.kind() {
92 hir::CallableKind::Function(_) => {
93 let ret_type = callable.return_type();
94 if !ret_type.is_unit() {
95 format_to!(res.signature, " -> {}", ret_type.display(db));
96 }
97 }
98 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
99 }
100 Some(res)
45} 101}
46 102
47fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { 103fn call_info_impl(
104 sema: &Semantics<RootDatabase>,
105 token: SyntaxToken,
106) -> Option<(hir::Callable, Option<usize>)> {
48 // Find the calling expression and it's NameRef 107 // Find the calling expression and it's NameRef
49 let calling_node = FnCallNode::with_node(&token.parent())?; 108 let calling_node = FnCallNode::with_node(&token.parent())?;
50 109
51 let signature = match &calling_node { 110 let callable = match &calling_node {
52 FnCallNode::CallExpr(call) => { 111 FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?,
53 //FIXME: Type::as_callable is broken 112 FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?,
54 let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; 113 };
55 match callable_def { 114 let active_param = if let Some(arg_list) = calling_node.arg_list() {
56 hir::CallableDefId::FunctionId(it) => { 115 // Number of arguments specified at the call site
57 let fn_def = it.into(); 116 let num_args_at_callsite = arg_list.args().count();
58 FunctionSignature::from_hir(sema.db, fn_def) 117
59 } 118 let arg_list_range = arg_list.syntax().text_range();
60 hir::CallableDefId::StructId(it) => { 119 if !arg_list_range.contains_inclusive(token.text_range().start()) {
61 FunctionSignature::from_struct(sema.db, it.into())? 120 mark::hit!(call_info_bad_offset);
62 } 121 return None;
63 hir::CallableDefId::EnumVariantId(it) => {
64 FunctionSignature::from_enum_variant(sema.db, it.into())?
65 }
66 }
67 }
68 FnCallNode::MethodCallExpr(method_call) => {
69 let function = sema.resolve_method_call(&method_call)?;
70 FunctionSignature::from_hir(sema.db, function)
71 }
72 FnCallNode::MacroCallExpr(macro_call) => {
73 let macro_def = sema.resolve_macro_call(&macro_call)?;
74 FunctionSignature::from_macro(sema.db, macro_def)?
75 } 122 }
123 let param = std::cmp::min(
124 num_args_at_callsite,
125 arg_list
126 .args()
127 .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
128 .count(),
129 );
130
131 Some(param)
132 } else {
133 None
76 }; 134 };
135 Some((callable, active_param))
136}
77 137
78 // If we have a calling expression let's find which argument we are on 138#[derive(Debug)]
79 let num_params = signature.parameters.len(); 139pub(crate) struct ActiveParameter {
80 140 pub(crate) ty: Type,
81 let active_parameter = match num_params { 141 pub(crate) name: String,
82 0 => None, 142}
83 1 if signature.has_self_param => None,
84 1 => Some(0),
85 _ => {
86 if let Some(arg_list) = calling_node.arg_list() {
87 // Number of arguments specified at the call site
88 let num_args_at_callsite = arg_list.args().count();
89
90 let arg_list_range = arg_list.syntax().text_range();
91 if !arg_list_range.contains_inclusive(token.text_range().start()) {
92 mark::hit!(call_info_bad_offset);
93 return None;
94 }
95 143
96 let mut param = std::cmp::min( 144impl ActiveParameter {
97 num_args_at_callsite, 145 pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
98 arg_list 146 let sema = Semantics::new(db);
99 .args() 147 let file = sema.parse(position.file_id);
100 .take_while(|arg| { 148 let file = file.syntax();
101 arg.syntax().text_range().end() <= token.text_range().start() 149 let token = file.token_at_offset(position.offset).next()?;
102 }) 150 let token = sema.descend_into_macros(token);
103 .count(), 151 Self::at_token(&sema, token)
104 ); 152 }
105
106 // If we are in a method account for `self`
107 if signature.has_self_param {
108 param += 1;
109 }
110 153
111 Some(param) 154 pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
112 } else { 155 let (signature, active_parameter) = call_info_impl(&sema, token)?;
113 None
114 }
115 }
116 };
117 156
118 Some(CallInfo { signature, active_parameter }) 157 let idx = active_parameter?;
158 let mut params = signature.params(sema.db);
159 let (pat, ty) = params.swap_remove(idx);
160 let name = pat?.to_string();
161 Some(ActiveParameter { ty, name })
162 }
119} 163}
120 164
121#[derive(Debug)] 165#[derive(Debug)]
122pub(crate) enum FnCallNode { 166pub(crate) enum FnCallNode {
123 CallExpr(ast::CallExpr), 167 CallExpr(ast::CallExpr),
124 MethodCallExpr(ast::MethodCallExpr), 168 MethodCallExpr(ast::MethodCallExpr),
125 MacroCallExpr(ast::MacroCall),
126} 169}
127 170
128impl FnCallNode { 171impl FnCallNode {
@@ -138,7 +181,6 @@ impl FnCallNode {
138 } 181 }
139 Some(FnCallNode::MethodCallExpr(it)) 182 Some(FnCallNode::MethodCallExpr(it))
140 }, 183 },
141 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
142 _ => None, 184 _ => None,
143 } 185 }
144 } 186 }
@@ -150,7 +192,6 @@ impl FnCallNode {
150 match node { 192 match node {
151 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), 193 ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
152 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), 194 ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)),
153 ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)),
154 _ => None, 195 _ => None,
155 } 196 }
156 } 197 }
@@ -166,8 +207,6 @@ impl FnCallNode {
166 FnCallNode::MethodCallExpr(call_expr) => { 207 FnCallNode::MethodCallExpr(call_expr) => {
167 call_expr.syntax().children().filter_map(ast::NameRef::cast).next() 208 call_expr.syntax().children().filter_map(ast::NameRef::cast).next()
168 } 209 }
169
170 FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(),
171 } 210 }
172 } 211 }
173 212
@@ -175,21 +214,10 @@ impl FnCallNode {
175 match self { 214 match self {
176 FnCallNode::CallExpr(expr) => expr.arg_list(), 215 FnCallNode::CallExpr(expr) => expr.arg_list(),
177 FnCallNode::MethodCallExpr(expr) => expr.arg_list(), 216 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
178 FnCallNode::MacroCallExpr(_) => None,
179 } 217 }
180 } 218 }
181} 219}
182 220
183impl CallInfo {
184 fn into_active_parameter(self) -> Option<ActiveParameter> {
185 let idx = self.active_parameter?;
186 let ty = self.signature.parameter_types.get(idx)?.clone();
187 let name = self.signature.parameter_names.get(idx)?.clone();
188 let res = ActiveParameter { ty, name };
189 Some(res)
190 }
191}
192
193#[cfg(test)] 221#[cfg(test)]
194mod tests { 222mod tests {
195 use expect::{expect, Expect}; 223 use expect::{expect, Expect};
@@ -202,20 +230,18 @@ mod tests {
202 let call_info = analysis.call_info(position).unwrap(); 230 let call_info = analysis.call_info(position).unwrap();
203 let actual = match call_info { 231 let actual = match call_info {
204 Some(call_info) => { 232 Some(call_info) => {
205 let docs = match &call_info.signature.doc { 233 let docs = match &call_info.doc {
206 None => "".to_string(), 234 None => "".to_string(),
207 Some(docs) => format!("{}\n------\n", docs.as_str()), 235 Some(docs) => format!("{}\n------\n", docs.as_str()),
208 }; 236 };
209 let params = call_info 237 let params = call_info
210 .signature 238 .parameter_labels()
211 .parameters
212 .iter()
213 .enumerate() 239 .enumerate()
214 .map(|(i, param)| { 240 .map(|(i, param)| {
215 if Some(i) == call_info.active_parameter { 241 if Some(i) == call_info.active_parameter {
216 format!("<{}>", param) 242 format!("<{}>", param)
217 } else { 243 } else {
218 param.clone() 244 param.to_string()
219 } 245 }
220 }) 246 })
221 .collect::<Vec<_>>() 247 .collect::<Vec<_>>()
@@ -296,10 +322,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
296fn bar() { foo(<|>3, ); } 322fn bar() { foo(<|>3, ); }
297"#, 323"#,
298 expect![[r#" 324 expect![[r#"
299 fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 325 fn foo(x: i32, y: {unknown}) -> u32
300 where T: Copy + Display, 326 (<x: i32>, y: {unknown})
301 U: Debug
302 (<x: T>, y: U)
303 "#]], 327 "#]],
304 ); 328 );
305 } 329 }
@@ -312,8 +336,7 @@ fn foo<T>() -> T where T: Copy + Display {}
312fn bar() { foo(<|>); } 336fn bar() { foo(<|>); }
313"#, 337"#,
314 expect![[r#" 338 expect![[r#"
315 fn foo<T>() -> T 339 fn foo() -> {unknown}
316 where T: Copy + Display
317 () 340 ()
318 "#]], 341 "#]],
319 ); 342 );
@@ -323,11 +346,14 @@ fn bar() { foo(<|>); }
323 fn test_fn_signature_for_impl() { 346 fn test_fn_signature_for_impl() {
324 check( 347 check(
325 r#" 348 r#"
326struct F; impl F { pub fn new() { F{}} } 349struct F;
327fn bar() {let _ : F = F::new(<|>);} 350impl F { pub fn new() { } }
351fn bar() {
352 let _ : F = F::new(<|>);
353}
328"#, 354"#,
329 expect![[r#" 355 expect![[r#"
330 pub fn new() 356 fn new()
331 () 357 ()
332 "#]], 358 "#]],
333 ); 359 );
@@ -346,8 +372,8 @@ fn bar() {
346} 372}
347"#, 373"#,
348 expect![[r#" 374 expect![[r#"
349 pub fn do_it(&self) 375 fn do_it(&self)
350 (&self) 376 ()
351 "#]], 377 "#]],
352 ); 378 );
353 } 379 }
@@ -365,8 +391,8 @@ fn bar() {
365} 391}
366"#, 392"#,
367 expect![[r#" 393 expect![[r#"
368 pub fn do_it(&self, x: i32) 394 fn do_it(&self, x: i32)
369 (&self, <x: i32>) 395 (<x: i32>)
370 "#]], 396 "#]],
371 ); 397 );
372 } 398 }
@@ -425,7 +451,7 @@ pub fn do() {
425 assert_eq!(6, my_crate::add_one(5)); 451 assert_eq!(6, my_crate::add_one(5));
426 ``` 452 ```
427 ------ 453 ------
428 pub fn add_one(x: i32) -> i32 454 fn add_one(x: i32) -> i32
429 (<x: i32>) 455 (<x: i32>)
430 "##]], 456 "##]],
431 ); 457 );
@@ -467,7 +493,7 @@ pub fn do_it() {
467 assert_eq!(6, my_crate::add_one(5)); 493 assert_eq!(6, my_crate::add_one(5));
468 ``` 494 ```
469 ------ 495 ------
470 pub fn add_one(x: i32) -> i32 496 fn add_one(x: i32) -> i32
471 (<x: i32>) 497 (<x: i32>)
472 "##]], 498 "##]],
473 ); 499 );
@@ -505,8 +531,8 @@ pub fn foo(mut r: WriteHandler<()>) {
505 531
506 By default this method stops actor's `Context`. 532 By default this method stops actor's `Context`.
507 ------ 533 ------
508 fn finished(&mut self, ctx: &mut Self::Context) 534 fn finished(&mut self, ctx: &mut {unknown})
509 (&mut self, <ctx: &mut Self::Context>) 535 (<ctx: &mut {unknown}>)
510 "#]], 536 "#]],
511 ); 537 );
512 } 538 }
@@ -539,7 +565,7 @@ fn main() {
539"#, 565"#,
540 expect![[r#" 566 expect![[r#"
541 fn bar(&self, _: u32) 567 fn bar(&self, _: u32)
542 (&self, <_: u32>) 568 (<_: u32>)
543 "#]], 569 "#]],
544 ); 570 );
545 } 571 }
@@ -549,15 +575,15 @@ fn main() {
549 check( 575 check(
550 r#" 576 r#"
551/// A cool tuple struct 577/// A cool tuple struct
552struct TS(u32, i32); 578struct S(u32, i32);
553fn main() { 579fn main() {
554 let s = TS(0, <|>); 580 let s = S(0, <|>);
555} 581}
556"#, 582"#,
557 expect![[r#" 583 expect![[r#"
558 A cool tuple struct 584 A cool tuple struct
559 ------ 585 ------
560 struct TS(u32, i32) -> TS 586 struct S(u32, i32)
561 (u32, <i32>) 587 (u32, <i32>)
562 "#]], 588 "#]],
563 ); 589 );
@@ -567,32 +593,19 @@ fn main() {
567 fn generic_struct() { 593 fn generic_struct() {
568 check( 594 check(
569 r#" 595 r#"
570struct TS<T>(T); 596struct S<T>(T);
571fn main() { 597fn main() {
572 let s = TS(<|>); 598 let s = S(<|>);
573} 599}
574"#, 600"#,
575 expect![[r#" 601 expect![[r#"
576 struct TS<T>(T) -> TS 602 struct S({unknown})
577 (<T>) 603 (<{unknown}>)
578 "#]], 604 "#]],
579 ); 605 );
580 } 606 }
581 607
582 #[test] 608 #[test]
583 fn cant_call_named_structs() {
584 check(
585 r#"
586struct TS { x: u32, y: i32 }
587fn main() {
588 let s = TS(<|>);
589}
590"#,
591 expect![[""]],
592 );
593 }
594
595 #[test]
596 fn works_for_enum_variants() { 609 fn works_for_enum_variants() {
597 check( 610 check(
598 r#" 611 r#"
@@ -612,27 +625,19 @@ fn main() {
612 expect![[r#" 625 expect![[r#"
613 A Variant 626 A Variant
614 ------ 627 ------
615 E::A(0: i32) 628 enum E::A(i32)
616 (<0: i32>) 629 (<i32>)
617 "#]], 630 "#]],
618 ); 631 );
619 } 632 }
620 633
621 #[test] 634 #[test]
622 fn cant_call_enum_records() { 635 fn cant_call_struct_record() {
623 check( 636 check(
624 r#" 637 r#"
625enum E { 638struct S { x: u32, y: i32 }
626 /// A Variant
627 A(i32),
628 /// Another
629 B,
630 /// And C
631 C { a: i32, b: i32 }
632}
633
634fn main() { 639fn main() {
635 let a = E::C(<|>); 640 let s = S(<|>);
636} 641}
637"#, 642"#,
638 expect![[""]], 643 expect![[""]],
@@ -640,24 +645,23 @@ fn main() {
640 } 645 }
641 646
642 #[test] 647 #[test]
643 fn fn_signature_for_macro() { 648 fn cant_call_enum_record() {
644 check( 649 check(
645 r#" 650 r#"
646/// empty macro 651enum E {
647macro_rules! foo { 652 /// A Variant
648 () => {} 653 A(i32),
654 /// Another
655 B,
656 /// And C
657 C { a: i32, b: i32 }
649} 658}
650 659
651fn f() { 660fn main() {
652 foo!(<|>); 661 let a = E::C(<|>);
653} 662}
654"#, 663"#,
655 expect![[r#" 664 expect![[""]],
656 empty macro
657 ------
658 foo!()
659 ()
660 "#]],
661 ); 665 );
662 } 666 }
663 667
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 64349dcb8..e6b4737aa 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -329,15 +329,10 @@ pub(crate) fn compute_score(
329 ty: &Type, 329 ty: &Type,
330 name: &str, 330 name: &str,
331) -> Option<CompletionScore> { 331) -> Option<CompletionScore> {
332 // FIXME: this should not fall back to string equality.
333 let ty = &ty.display(ctx.db).to_string();
334 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { 332 let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
335 mark::hit!(record_field_type_match); 333 mark::hit!(record_field_type_match);
336 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; 334 let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
337 ( 335 (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db))
338 struct_field.name(ctx.db).to_string(),
339 struct_field.signature_ty(ctx.db).display(ctx.db).to_string(),
340 )
341 } else if let Some(active_parameter) = &ctx.active_parameter { 336 } else if let Some(active_parameter) = &ctx.active_parameter {
342 mark::hit!(active_param_type_match); 337 mark::hit!(active_param_type_match);
343 (active_parameter.name.clone(), active_parameter.ty.clone()) 338 (active_parameter.name.clone(), active_parameter.ty.clone())
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index 1d39544d3..709a85f65 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -149,27 +149,6 @@ impl FunctionSignature {
149 has_self_param: false, 149 has_self_param: false,
150 }) 150 })
151 } 151 }
152
153 pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
154 let node: ast::MacroCall = macro_def.source(db).value;
155
156 let params = vec![];
157
158 Some(FunctionSignature {
159 kind: CallableKind::Macro,
160 visibility: None,
161 qualifier: Default::default(),
162 name: node.name().map(|n| n.text().to_string()),
163 ret_type: None,
164 parameters: params,
165 parameter_names: vec![],
166 parameter_types: vec![],
167 generic_parameters: vec![],
168 where_predicates: vec![],
169 doc: macro_def.docs(db),
170 has_self_param: false,
171 })
172 }
173} 152}
174 153
175impl From<&'_ ast::FnDef> for FunctionSignature { 154impl From<&'_ ast::FnDef> for FunctionSignature {
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 3cbae8a45..2e021f032 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -322,15 +322,15 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
322 match expr { 322 match expr {
323 ast::Expr::CallExpr(expr) => { 323 ast::Expr::CallExpr(expr) => {
324 // FIXME: Type::as_callable is broken for closures 324 // FIXME: Type::as_callable is broken for closures
325 let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; 325 let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db)?;
326 match callable_def { 326 match callable.kind() {
327 hir::CallableDefId::FunctionId(it) => { 327 hir::CallableKind::Function(it) => {
328 Some(FunctionSignature::from_hir(sema.db, it.into())) 328 Some(FunctionSignature::from_hir(sema.db, it.into()))
329 } 329 }
330 hir::CallableDefId::StructId(it) => { 330 hir::CallableKind::TupleStruct(it) => {
331 FunctionSignature::from_struct(sema.db, it.into()) 331 FunctionSignature::from_struct(sema.db, it.into())
332 } 332 }
333 hir::CallableDefId::EnumVariantId(it) => { 333 hir::CallableKind::TupleEnumVariant(it) => {
334 FunctionSignature::from_enum_variant(sema.db, it.into()) 334 FunctionSignature::from_enum_variant(sema.db, it.into())
335 } 335 }
336 } 336 }
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index d28c700f1..447d73fd4 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -553,21 +553,12 @@ pub(crate) fn handle_signature_help(
553 let _p = profile("handle_signature_help"); 553 let _p = profile("handle_signature_help");
554 let position = from_proto::file_position(&snap, params.text_document_position_params)?; 554 let position = from_proto::file_position(&snap, params.text_document_position_params)?;
555 let call_info = match snap.analysis.call_info(position)? { 555 let call_info = match snap.analysis.call_info(position)? {
556 None => return Ok(None),
557 Some(it) => it, 556 Some(it) => it,
557 None => return Ok(None),
558 }; 558 };
559 let concise = !snap.config.call_info_full; 559 let concise = !snap.config.call_info_full;
560 let mut active_parameter = call_info.active_parameter.map(|it| it as i64); 560 let res = to_proto::signature_help(call_info, concise);
561 if concise && call_info.signature.has_self_param { 561 Ok(Some(res))
562 active_parameter = active_parameter.map(|it| it.saturating_sub(1));
563 }
564 let sig_info = to_proto::signature_information(call_info.signature, concise);
565
566 Ok(Some(lsp_types::SignatureHelp {
567 signatures: vec![sig_info],
568 active_signature: Some(0),
569 active_parameter,
570 }))
571} 562}
572 563
573pub(crate) fn handle_hover( 564pub(crate) fn handle_hover(
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 2fcae9ca3..43fc52848 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -4,8 +4,8 @@ use std::path::{self, Path};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::{FileId, FileRange}; 5use ra_db::{FileId, FileRange};
6use ra_ide::{ 6use ra_ide::{
7 Assist, AssistKind, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, 7 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation,
8 FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, 8 FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
9 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, 9 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
10 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, 10 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
11}; 11};
@@ -219,29 +219,30 @@ pub(crate) fn completion_item(
219 res 219 res
220} 220}
221 221
222pub(crate) fn signature_information( 222pub(crate) fn signature_help(call_info: CallInfo, concise: bool) -> lsp_types::SignatureHelp {
223 signature: FunctionSignature, 223 let parameters = call_info
224 concise: bool, 224 .parameter_labels()
225) -> lsp_types::SignatureInformation { 225 .map(|label| lsp_types::ParameterInformation {
226 let (label, documentation, params) = if concise { 226 label: lsp_types::ParameterLabel::Simple(label.to_string()),
227 let mut params = signature.parameters;
228 if signature.has_self_param {
229 params.remove(0);
230 }
231 (params.join(", "), None, params)
232 } else {
233 (signature.to_string(), signature.doc.map(documentation), signature.parameters)
234 };
235
236 let parameters: Vec<lsp_types::ParameterInformation> = params
237 .into_iter()
238 .map(|param| lsp_types::ParameterInformation {
239 label: lsp_types::ParameterLabel::Simple(param),
240 documentation: None, 227 documentation: None,
241 }) 228 })
242 .collect(); 229 .collect();
243 230
244 lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) } 231 let label = if concise { call_info.parameter_labels().join(", ") } else { call_info.signature };
232 let documentation = call_info.doc.map(|doc| {
233 lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent {
234 kind: lsp_types::MarkupKind::Markdown,
235 value: doc,
236 })
237 });
238
239 let signature =
240 lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) };
241 lsp_types::SignatureHelp {
242 signatures: vec![signature],
243 active_signature: None,
244 active_parameter: call_info.active_parameter.map(|it| it as i64),
245 }
245} 246}
246 247
247pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { 248pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint {