diff options
author | Aleksey Kladov <[email protected]> | 2020-07-16 12:00:56 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-07-16 17:03:04 +0100 |
commit | ff0312fa32715ce42f134fd9f049c4df5956d042 (patch) | |
tree | b514e34d3486a650fef35e29396a810ee7741cd1 /crates | |
parent | 9210fcc076808e53e9bde84be26307fc0dc7d688 (diff) |
Semantical call info
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 76 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/path_resolution.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/call_hierarchy.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide/src/call_info.rs | 332 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 7 | ||||
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 21 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 15 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 43 |
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 |
2 | use std::sync::Arc; | 2 | use std::{iter, sync::Arc}; |
3 | 3 | ||
4 | use arrayvec::ArrayVec; | 4 | use arrayvec::ArrayVec; |
5 | use either::Either; | 5 | use 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::{ | |||
25 | use hir_ty::{ | 26 | use 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 | }; |
31 | use ra_db::{CrateId, Edition, FileId}; | 32 | use ra_db::{CrateId, Edition, FileId}; |
32 | use ra_prof::profile; | 33 | use ra_prof::profile; |
@@ -40,7 +41,7 @@ use stdx::impl_from; | |||
40 | use crate::{ | 41 | use 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)] | ||
1525 | pub struct Callable { | ||
1526 | ty: Type, | ||
1527 | sig: FnSig, | ||
1528 | id: CallableDefId, | ||
1529 | pub(crate) is_bound_method: bool, | ||
1530 | } | ||
1531 | |||
1532 | pub enum CallableKind { | ||
1533 | Function(Function), | ||
1534 | TupleStruct(Struct), | ||
1535 | TupleEnumVariant(EnumVariant), | ||
1536 | } | ||
1537 | |||
1538 | impl 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)] |
1517 | pub enum ScopeDef { | 1579 | pub 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 | ||
33 | pub use crate::{ | 33 | pub 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 | }; |
54 | pub use hir_expand::{ | 54 | pub 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 | }; |
58 | pub use hir_ty::{display::HirDisplay, CallableDefId}; | 59 | pub 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 | ||
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, TraitId, VariantId, | 9 | AsMacroCall, FunctionId, TraitId, VariantId, |
10 | }; | 10 | }; |
11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; | 11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use 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 | }; |
30 | use resolver::TypeNs; | 30 | use 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, ¶m) | 389 | self.analyze(param.syntax()).type_of_self(self.db, ¶m) |
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 | }; |
19 | use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; | 19 | use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; |
20 | use hir_ty::{ | 20 | use 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(¯o_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 |
2 | use hir::Semantics; | 2 | use hir::{Docs, HirDisplay, Semantics, Type}; |
3 | use ra_ide_db::RootDatabase; | 3 | use ra_ide_db::RootDatabase; |
4 | use ra_syntax::{ | 4 | use 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 | }; |
8 | use stdx::format_to; | ||
8 | use test_utils::mark; | 9 | use test_utils::mark; |
9 | 10 | ||
10 | use crate::{FilePosition, FunctionSignature}; | 11 | use 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)] |
15 | pub struct CallInfo { | 16 | pub 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 | |||
23 | impl 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)?; |
31 | pub(crate) struct ActiveParameter { | ||
32 | /// FIXME: should be `Type` and `Name | ||
33 | pub(crate) ty: String, | ||
34 | pub(crate) name: String, | ||
35 | } | ||
36 | 50 | ||
37 | impl 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 | ||
47 | fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { | 103 | fn 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(¯o_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(); | 139 | pub(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( | 144 | impl 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)] |
122 | pub(crate) enum FnCallNode { | 166 | pub(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 | ||
128 | impl FnCallNode { | 171 | impl 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 | ||
183 | impl 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)] |
194 | mod tests { | 222 | mod 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 | |||
296 | fn bar() { foo(<|>3, ); } | 322 | fn 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 {} | |||
312 | fn bar() { foo(<|>); } | 336 | fn 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#" |
326 | struct F; impl F { pub fn new() { F{}} } | 349 | struct F; |
327 | fn bar() {let _ : F = F::new(<|>);} | 350 | impl F { pub fn new() { } } |
351 | fn 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 |
552 | struct TS(u32, i32); | 578 | struct S(u32, i32); |
553 | fn main() { | 579 | fn 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#" |
570 | struct TS<T>(T); | 596 | struct S<T>(T); |
571 | fn main() { | 597 | fn 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#" | ||
586 | struct TS { x: u32, y: i32 } | ||
587 | fn 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#" |
625 | enum E { | 638 | struct 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 | |||
634 | fn main() { | 639 | fn 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 | 651 | enum E { |
647 | macro_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 | ||
651 | fn f() { | 660 | fn 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 | ||
175 | impl From<&'_ ast::FnDef> for FunctionSignature { | 154 | impl 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 | ||
573 | pub(crate) fn handle_hover( | 564 | pub(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}; | |||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_db::{FileId, FileRange}; | 5 | use ra_db::{FileId, FileRange}; |
6 | use ra_ide::{ | 6 | use 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 | ||
222 | pub(crate) fn signature_information( | 222 | pub(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 | ||
247 | pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { | 248 | pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { |