diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-16 17:50:37 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-16 17:50:37 +0100 |
commit | 081596dd584ac39fbfa6a7e47dfe9dd4a58c362a (patch) | |
tree | b6d564a63068530ef3aabb8855699bf20c45a608 | |
parent | 9210fcc076808e53e9bde84be26307fc0dc7d688 (diff) | |
parent | e1e79cf0648624e7a3787d0013c0c7e86210772f (diff) |
Merge #5413
5413: Semantical call info r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 86 | ||||
-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 | 361 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide/src/display.rs | 11 | ||||
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 61 | ||||
-rw-r--r-- | crates/ra_ide/src/file_structure.rs (renamed from crates/ra_ide/src/display/structure.rs) | 0 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 14 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 37 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli.rs | 8 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 19 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 83 |
18 files changed, 452 insertions, 313 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 9891b0785..eb6a14eda 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,70 @@ 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( | ||
1556 | &self, | ||
1557 | db: &dyn HirDatabase, | ||
1558 | ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> { | ||
1559 | let types = self | ||
1560 | .sig | ||
1561 | .params() | ||
1562 | .iter() | ||
1563 | .skip(if self.is_bound_method { 1 } else { 0 }) | ||
1564 | .map(|ty| self.ty.derived(ty.clone())); | ||
1565 | let patterns = match self.id { | ||
1566 | CallableDefId::FunctionId(func) => { | ||
1567 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
1568 | src.value.param_list().map(|param_list| { | ||
1569 | param_list | ||
1570 | .self_param() | ||
1571 | .map(|it| Some(Either::Left(it))) | ||
1572 | .filter(|_| !self.is_bound_method) | ||
1573 | .into_iter() | ||
1574 | .chain(param_list.params().map(|it| it.pat().map(Either::Right))) | ||
1575 | }) | ||
1576 | } | ||
1577 | CallableDefId::StructId(_) => None, | ||
1578 | CallableDefId::EnumVariantId(_) => None, | ||
1579 | }; | ||
1580 | patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() | ||
1581 | } | ||
1582 | pub fn return_type(&self) -> Type { | ||
1583 | self.ty.derived(self.sig.ret().clone()) | ||
1584 | } | ||
1585 | } | ||
1586 | |||
1515 | /// For IDE only | 1587 | /// For IDE only |
1516 | #[derive(Debug)] | 1588 | #[derive(Debug)] |
1517 | pub enum ScopeDef { | 1589 | 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..35a8a0dc5 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs | |||
@@ -1,20 +1,42 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use hir::Semantics; | 2 | use either::Either; |
3 | use hir::{Docs, HirDisplay, Semantics, Type}; | ||
3 | use ra_ide_db::RootDatabase; | 4 | use ra_ide_db::RootDatabase; |
4 | use ra_syntax::{ | 5 | use ra_syntax::{ |
5 | ast::{self, ArgListOwner}, | 6 | ast::{self, ArgListOwner}, |
6 | match_ast, AstNode, SyntaxNode, SyntaxToken, | 7 | match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, |
7 | }; | 8 | }; |
9 | use stdx::format_to; | ||
8 | use test_utils::mark; | 10 | use test_utils::mark; |
9 | 11 | ||
10 | use crate::{FilePosition, FunctionSignature}; | 12 | use crate::FilePosition; |
11 | 13 | ||
12 | /// Contains information about a call site. Specifically the | 14 | /// Contains information about a call site. Specifically the |
13 | /// `FunctionSignature`and current parameter. | 15 | /// `FunctionSignature`and current parameter. |
14 | #[derive(Debug)] | 16 | #[derive(Debug)] |
15 | pub struct CallInfo { | 17 | pub struct CallInfo { |
16 | pub signature: FunctionSignature, | 18 | pub doc: Option<String>, |
19 | pub signature: String, | ||
17 | pub active_parameter: Option<usize>, | 20 | pub active_parameter: Option<usize>, |
21 | parameters: Vec<TextRange>, | ||
22 | } | ||
23 | |||
24 | impl CallInfo { | ||
25 | pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ { | ||
26 | self.parameters.iter().map(move |&it| &self.signature[it]) | ||
27 | } | ||
28 | pub fn parameter_ranges(&self) -> &[TextRange] { | ||
29 | &self.parameters | ||
30 | } | ||
31 | fn push_param(&mut self, param: &str) { | ||
32 | if !self.signature.ends_with('(') { | ||
33 | self.signature.push_str(", "); | ||
34 | } | ||
35 | let start = TextSize::of(&self.signature); | ||
36 | self.signature.push_str(param); | ||
37 | let end = TextSize::of(&self.signature); | ||
38 | self.parameters.push(TextRange::new(start, end)) | ||
39 | } | ||
18 | } | 40 | } |
19 | 41 | ||
20 | /// Computes parameter information for the given call expression. | 42 | /// Computes parameter information for the given call expression. |
@@ -24,105 +46,130 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
24 | let file = file.syntax(); | 46 | let file = file.syntax(); |
25 | let token = file.token_at_offset(position.offset).next()?; | 47 | let token = file.token_at_offset(position.offset).next()?; |
26 | let token = sema.descend_into_macros(token); | 48 | let token = sema.descend_into_macros(token); |
27 | call_info_for_token(&sema, token) | ||
28 | } | ||
29 | 49 | ||
30 | #[derive(Debug)] | 50 | 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 | 51 | ||
37 | impl ActiveParameter { | 52 | let mut res = |
38 | pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { | 53 | CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter }; |
39 | call_info(db, position)?.into_active_parameter() | 54 | |
55 | match callable.kind() { | ||
56 | hir::CallableKind::Function(func) => { | ||
57 | res.doc = func.docs(db).map(|it| it.as_str().to_string()); | ||
58 | format_to!(res.signature, "fn {}", func.name(db)); | ||
59 | } | ||
60 | hir::CallableKind::TupleStruct(strukt) => { | ||
61 | res.doc = strukt.docs(db).map(|it| it.as_str().to_string()); | ||
62 | format_to!(res.signature, "struct {}", strukt.name(db)); | ||
63 | } | ||
64 | hir::CallableKind::TupleEnumVariant(variant) => { | ||
65 | res.doc = variant.docs(db).map(|it| it.as_str().to_string()); | ||
66 | format_to!( | ||
67 | res.signature, | ||
68 | "enum {}::{}", | ||
69 | variant.parent_enum(db).name(db), | ||
70 | variant.name(db) | ||
71 | ); | ||
72 | } | ||
40 | } | 73 | } |
41 | 74 | ||
42 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { | 75 | res.signature.push('('); |
43 | call_info_for_token(sema, token)?.into_active_parameter() | 76 | { |
77 | if let Some(self_param) = callable.receiver_param(db) { | ||
78 | format_to!(res.signature, "{}", self_param) | ||
79 | } | ||
80 | let mut buf = String::new(); | ||
81 | for (pat, ty) in callable.params(db) { | ||
82 | buf.clear(); | ||
83 | if let Some(pat) = pat { | ||
84 | match pat { | ||
85 | Either::Left(_self) => format_to!(buf, "self: "), | ||
86 | Either::Right(pat) => format_to!(buf, "{}: ", pat), | ||
87 | } | ||
88 | } | ||
89 | format_to!(buf, "{}", ty.display(db)); | ||
90 | res.push_param(&buf); | ||
91 | } | ||
44 | } | 92 | } |
93 | res.signature.push(')'); | ||
94 | |||
95 | match callable.kind() { | ||
96 | hir::CallableKind::Function(_) => { | ||
97 | let ret_type = callable.return_type(); | ||
98 | if !ret_type.is_unit() { | ||
99 | format_to!(res.signature, " -> {}", ret_type.display(db)); | ||
100 | } | ||
101 | } | ||
102 | hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} | ||
103 | } | ||
104 | Some(res) | ||
45 | } | 105 | } |
46 | 106 | ||
47 | fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { | 107 | fn call_info_impl( |
108 | sema: &Semantics<RootDatabase>, | ||
109 | token: SyntaxToken, | ||
110 | ) -> Option<(hir::Callable, Option<usize>)> { | ||
48 | // Find the calling expression and it's NameRef | 111 | // Find the calling expression and it's NameRef |
49 | let calling_node = FnCallNode::with_node(&token.parent())?; | 112 | let calling_node = FnCallNode::with_node(&token.parent())?; |
50 | 113 | ||
51 | let signature = match &calling_node { | 114 | let callable = match &calling_node { |
52 | FnCallNode::CallExpr(call) => { | 115 | FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?, |
53 | //FIXME: Type::as_callable is broken | 116 | FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?, |
54 | let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; | 117 | }; |
55 | match callable_def { | 118 | let active_param = if let Some(arg_list) = calling_node.arg_list() { |
56 | hir::CallableDefId::FunctionId(it) => { | 119 | // Number of arguments specified at the call site |
57 | let fn_def = it.into(); | 120 | let num_args_at_callsite = arg_list.args().count(); |
58 | FunctionSignature::from_hir(sema.db, fn_def) | 121 | |
59 | } | 122 | let arg_list_range = arg_list.syntax().text_range(); |
60 | hir::CallableDefId::StructId(it) => { | 123 | if !arg_list_range.contains_inclusive(token.text_range().start()) { |
61 | FunctionSignature::from_struct(sema.db, it.into())? | 124 | mark::hit!(call_info_bad_offset); |
62 | } | 125 | 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 | } | 126 | } |
127 | let param = std::cmp::min( | ||
128 | num_args_at_callsite, | ||
129 | arg_list | ||
130 | .args() | ||
131 | .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) | ||
132 | .count(), | ||
133 | ); | ||
134 | |||
135 | Some(param) | ||
136 | } else { | ||
137 | None | ||
76 | }; | 138 | }; |
139 | Some((callable, active_param)) | ||
140 | } | ||
77 | 141 | ||
78 | // If we have a calling expression let's find which argument we are on | 142 | #[derive(Debug)] |
79 | let num_params = signature.parameters.len(); | 143 | pub(crate) struct ActiveParameter { |
80 | 144 | pub(crate) ty: Type, | |
81 | let active_parameter = match num_params { | 145 | pub(crate) name: String, |
82 | 0 => None, | 146 | } |
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 | 147 | ||
96 | let mut param = std::cmp::min( | 148 | impl ActiveParameter { |
97 | num_args_at_callsite, | 149 | pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { |
98 | arg_list | 150 | let sema = Semantics::new(db); |
99 | .args() | 151 | let file = sema.parse(position.file_id); |
100 | .take_while(|arg| { | 152 | let file = file.syntax(); |
101 | arg.syntax().text_range().end() <= token.text_range().start() | 153 | let token = file.token_at_offset(position.offset).next()?; |
102 | }) | 154 | let token = sema.descend_into_macros(token); |
103 | .count(), | 155 | Self::at_token(&sema, token) |
104 | ); | 156 | } |
105 | |||
106 | // If we are in a method account for `self` | ||
107 | if signature.has_self_param { | ||
108 | param += 1; | ||
109 | } | ||
110 | 157 | ||
111 | Some(param) | 158 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { |
112 | } else { | 159 | let (signature, active_parameter) = call_info_impl(&sema, token)?; |
113 | None | ||
114 | } | ||
115 | } | ||
116 | }; | ||
117 | 160 | ||
118 | Some(CallInfo { signature, active_parameter }) | 161 | let idx = active_parameter?; |
162 | let mut params = signature.params(sema.db); | ||
163 | let (pat, ty) = params.swap_remove(idx); | ||
164 | let name = pat?.to_string(); | ||
165 | Some(ActiveParameter { ty, name }) | ||
166 | } | ||
119 | } | 167 | } |
120 | 168 | ||
121 | #[derive(Debug)] | 169 | #[derive(Debug)] |
122 | pub(crate) enum FnCallNode { | 170 | pub(crate) enum FnCallNode { |
123 | CallExpr(ast::CallExpr), | 171 | CallExpr(ast::CallExpr), |
124 | MethodCallExpr(ast::MethodCallExpr), | 172 | MethodCallExpr(ast::MethodCallExpr), |
125 | MacroCallExpr(ast::MacroCall), | ||
126 | } | 173 | } |
127 | 174 | ||
128 | impl FnCallNode { | 175 | impl FnCallNode { |
@@ -138,7 +185,6 @@ impl FnCallNode { | |||
138 | } | 185 | } |
139 | Some(FnCallNode::MethodCallExpr(it)) | 186 | Some(FnCallNode::MethodCallExpr(it)) |
140 | }, | 187 | }, |
141 | ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)), | ||
142 | _ => None, | 188 | _ => None, |
143 | } | 189 | } |
144 | } | 190 | } |
@@ -150,7 +196,6 @@ impl FnCallNode { | |||
150 | match node { | 196 | match node { |
151 | ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), | 197 | ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), |
152 | ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), | 198 | ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), |
153 | ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)), | ||
154 | _ => None, | 199 | _ => None, |
155 | } | 200 | } |
156 | } | 201 | } |
@@ -166,8 +211,6 @@ impl FnCallNode { | |||
166 | FnCallNode::MethodCallExpr(call_expr) => { | 211 | FnCallNode::MethodCallExpr(call_expr) => { |
167 | call_expr.syntax().children().filter_map(ast::NameRef::cast).next() | 212 | call_expr.syntax().children().filter_map(ast::NameRef::cast).next() |
168 | } | 213 | } |
169 | |||
170 | FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(), | ||
171 | } | 214 | } |
172 | } | 215 | } |
173 | 216 | ||
@@ -175,21 +218,10 @@ impl FnCallNode { | |||
175 | match self { | 218 | match self { |
176 | FnCallNode::CallExpr(expr) => expr.arg_list(), | 219 | FnCallNode::CallExpr(expr) => expr.arg_list(), |
177 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), | 220 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), |
178 | FnCallNode::MacroCallExpr(_) => None, | ||
179 | } | 221 | } |
180 | } | 222 | } |
181 | } | 223 | } |
182 | 224 | ||
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)] | 225 | #[cfg(test)] |
194 | mod tests { | 226 | mod tests { |
195 | use expect::{expect, Expect}; | 227 | use expect::{expect, Expect}; |
@@ -202,20 +234,18 @@ mod tests { | |||
202 | let call_info = analysis.call_info(position).unwrap(); | 234 | let call_info = analysis.call_info(position).unwrap(); |
203 | let actual = match call_info { | 235 | let actual = match call_info { |
204 | Some(call_info) => { | 236 | Some(call_info) => { |
205 | let docs = match &call_info.signature.doc { | 237 | let docs = match &call_info.doc { |
206 | None => "".to_string(), | 238 | None => "".to_string(), |
207 | Some(docs) => format!("{}\n------\n", docs.as_str()), | 239 | Some(docs) => format!("{}\n------\n", docs.as_str()), |
208 | }; | 240 | }; |
209 | let params = call_info | 241 | let params = call_info |
210 | .signature | 242 | .parameter_labels() |
211 | .parameters | ||
212 | .iter() | ||
213 | .enumerate() | 243 | .enumerate() |
214 | .map(|(i, param)| { | 244 | .map(|(i, param)| { |
215 | if Some(i) == call_info.active_parameter { | 245 | if Some(i) == call_info.active_parameter { |
216 | format!("<{}>", param) | 246 | format!("<{}>", param) |
217 | } else { | 247 | } else { |
218 | param.clone() | 248 | param.to_string() |
219 | } | 249 | } |
220 | }) | 250 | }) |
221 | .collect::<Vec<_>>() | 251 | .collect::<Vec<_>>() |
@@ -296,10 +326,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | |||
296 | fn bar() { foo(<|>3, ); } | 326 | fn bar() { foo(<|>3, ); } |
297 | "#, | 327 | "#, |
298 | expect![[r#" | 328 | expect![[r#" |
299 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | 329 | fn foo(x: i32, y: {unknown}) -> u32 |
300 | where T: Copy + Display, | 330 | (<x: i32>, y: {unknown}) |
301 | U: Debug | ||
302 | (<x: T>, y: U) | ||
303 | "#]], | 331 | "#]], |
304 | ); | 332 | ); |
305 | } | 333 | } |
@@ -312,8 +340,7 @@ fn foo<T>() -> T where T: Copy + Display {} | |||
312 | fn bar() { foo(<|>); } | 340 | fn bar() { foo(<|>); } |
313 | "#, | 341 | "#, |
314 | expect![[r#" | 342 | expect![[r#" |
315 | fn foo<T>() -> T | 343 | fn foo() -> {unknown} |
316 | where T: Copy + Display | ||
317 | () | 344 | () |
318 | "#]], | 345 | "#]], |
319 | ); | 346 | ); |
@@ -323,11 +350,14 @@ fn bar() { foo(<|>); } | |||
323 | fn test_fn_signature_for_impl() { | 350 | fn test_fn_signature_for_impl() { |
324 | check( | 351 | check( |
325 | r#" | 352 | r#" |
326 | struct F; impl F { pub fn new() { F{}} } | 353 | struct F; |
327 | fn bar() {let _ : F = F::new(<|>);} | 354 | impl F { pub fn new() { } } |
355 | fn bar() { | ||
356 | let _ : F = F::new(<|>); | ||
357 | } | ||
328 | "#, | 358 | "#, |
329 | expect![[r#" | 359 | expect![[r#" |
330 | pub fn new() | 360 | fn new() |
331 | () | 361 | () |
332 | "#]], | 362 | "#]], |
333 | ); | 363 | ); |
@@ -346,8 +376,8 @@ fn bar() { | |||
346 | } | 376 | } |
347 | "#, | 377 | "#, |
348 | expect![[r#" | 378 | expect![[r#" |
349 | pub fn do_it(&self) | 379 | fn do_it(&self) |
350 | (&self) | 380 | () |
351 | "#]], | 381 | "#]], |
352 | ); | 382 | ); |
353 | } | 383 | } |
@@ -357,16 +387,33 @@ fn bar() { | |||
357 | check( | 387 | check( |
358 | r#" | 388 | r#" |
359 | struct S; | 389 | struct S; |
360 | impl S { pub fn do_it(&self, x: i32) {} } | 390 | impl S { |
391 | fn foo(&self, x: i32) {} | ||
392 | } | ||
361 | 393 | ||
362 | fn bar() { | 394 | fn main() { S.foo(<|>); } |
363 | let s: S = S; | 395 | "#, |
364 | s.do_it(<|>); | 396 | expect![[r#" |
397 | fn foo(&self, x: i32) | ||
398 | (<x: i32>) | ||
399 | "#]], | ||
400 | ); | ||
401 | } | ||
402 | |||
403 | #[test] | ||
404 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { | ||
405 | check( | ||
406 | r#" | ||
407 | struct S; | ||
408 | impl S { | ||
409 | fn foo(&self, x: i32) {} | ||
365 | } | 410 | } |
411 | |||
412 | fn main() { S::foo(<|>); } | ||
366 | "#, | 413 | "#, |
367 | expect![[r#" | 414 | expect![[r#" |
368 | pub fn do_it(&self, x: i32) | 415 | fn foo(self: &S, x: i32) |
369 | (&self, <x: i32>) | 416 | (<self: &S>, x: i32) |
370 | "#]], | 417 | "#]], |
371 | ); | 418 | ); |
372 | } | 419 | } |
@@ -425,7 +472,7 @@ pub fn do() { | |||
425 | assert_eq!(6, my_crate::add_one(5)); | 472 | assert_eq!(6, my_crate::add_one(5)); |
426 | ``` | 473 | ``` |
427 | ------ | 474 | ------ |
428 | pub fn add_one(x: i32) -> i32 | 475 | fn add_one(x: i32) -> i32 |
429 | (<x: i32>) | 476 | (<x: i32>) |
430 | "##]], | 477 | "##]], |
431 | ); | 478 | ); |
@@ -467,7 +514,7 @@ pub fn do_it() { | |||
467 | assert_eq!(6, my_crate::add_one(5)); | 514 | assert_eq!(6, my_crate::add_one(5)); |
468 | ``` | 515 | ``` |
469 | ------ | 516 | ------ |
470 | pub fn add_one(x: i32) -> i32 | 517 | fn add_one(x: i32) -> i32 |
471 | (<x: i32>) | 518 | (<x: i32>) |
472 | "##]], | 519 | "##]], |
473 | ); | 520 | ); |
@@ -505,8 +552,8 @@ pub fn foo(mut r: WriteHandler<()>) { | |||
505 | 552 | ||
506 | By default this method stops actor's `Context`. | 553 | By default this method stops actor's `Context`. |
507 | ------ | 554 | ------ |
508 | fn finished(&mut self, ctx: &mut Self::Context) | 555 | fn finished(&mut self, ctx: &mut {unknown}) |
509 | (&mut self, <ctx: &mut Self::Context>) | 556 | (<ctx: &mut {unknown}>) |
510 | "#]], | 557 | "#]], |
511 | ); | 558 | ); |
512 | } | 559 | } |
@@ -539,7 +586,7 @@ fn main() { | |||
539 | "#, | 586 | "#, |
540 | expect![[r#" | 587 | expect![[r#" |
541 | fn bar(&self, _: u32) | 588 | fn bar(&self, _: u32) |
542 | (&self, <_: u32>) | 589 | (<_: u32>) |
543 | "#]], | 590 | "#]], |
544 | ); | 591 | ); |
545 | } | 592 | } |
@@ -549,15 +596,15 @@ fn main() { | |||
549 | check( | 596 | check( |
550 | r#" | 597 | r#" |
551 | /// A cool tuple struct | 598 | /// A cool tuple struct |
552 | struct TS(u32, i32); | 599 | struct S(u32, i32); |
553 | fn main() { | 600 | fn main() { |
554 | let s = TS(0, <|>); | 601 | let s = S(0, <|>); |
555 | } | 602 | } |
556 | "#, | 603 | "#, |
557 | expect![[r#" | 604 | expect![[r#" |
558 | A cool tuple struct | 605 | A cool tuple struct |
559 | ------ | 606 | ------ |
560 | struct TS(u32, i32) -> TS | 607 | struct S(u32, i32) |
561 | (u32, <i32>) | 608 | (u32, <i32>) |
562 | "#]], | 609 | "#]], |
563 | ); | 610 | ); |
@@ -567,32 +614,19 @@ fn main() { | |||
567 | fn generic_struct() { | 614 | fn generic_struct() { |
568 | check( | 615 | check( |
569 | r#" | 616 | r#" |
570 | struct TS<T>(T); | 617 | struct S<T>(T); |
571 | fn main() { | 618 | fn main() { |
572 | let s = TS(<|>); | 619 | let s = S(<|>); |
573 | } | 620 | } |
574 | "#, | 621 | "#, |
575 | expect![[r#" | 622 | expect![[r#" |
576 | struct TS<T>(T) -> TS | 623 | struct S({unknown}) |
577 | (<T>) | 624 | (<{unknown}>) |
578 | "#]], | 625 | "#]], |
579 | ); | 626 | ); |
580 | } | 627 | } |
581 | 628 | ||
582 | #[test] | 629 | #[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() { | 630 | fn works_for_enum_variants() { |
597 | check( | 631 | check( |
598 | r#" | 632 | r#" |
@@ -612,27 +646,19 @@ fn main() { | |||
612 | expect![[r#" | 646 | expect![[r#" |
613 | A Variant | 647 | A Variant |
614 | ------ | 648 | ------ |
615 | E::A(0: i32) | 649 | enum E::A(i32) |
616 | (<0: i32>) | 650 | (<i32>) |
617 | "#]], | 651 | "#]], |
618 | ); | 652 | ); |
619 | } | 653 | } |
620 | 654 | ||
621 | #[test] | 655 | #[test] |
622 | fn cant_call_enum_records() { | 656 | fn cant_call_struct_record() { |
623 | check( | 657 | check( |
624 | r#" | 658 | r#" |
625 | enum E { | 659 | 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() { | 660 | fn main() { |
635 | let a = E::C(<|>); | 661 | let s = S(<|>); |
636 | } | 662 | } |
637 | "#, | 663 | "#, |
638 | expect![[""]], | 664 | expect![[""]], |
@@ -640,24 +666,23 @@ fn main() { | |||
640 | } | 666 | } |
641 | 667 | ||
642 | #[test] | 668 | #[test] |
643 | fn fn_signature_for_macro() { | 669 | fn cant_call_enum_record() { |
644 | check( | 670 | check( |
645 | r#" | 671 | r#" |
646 | /// empty macro | 672 | enum E { |
647 | macro_rules! foo { | 673 | /// A Variant |
648 | () => {} | 674 | A(i32), |
675 | /// Another | ||
676 | B, | ||
677 | /// And C | ||
678 | C { a: i32, b: i32 } | ||
649 | } | 679 | } |
650 | 680 | ||
651 | fn f() { | 681 | fn main() { |
652 | foo!(<|>); | 682 | let a = E::C(<|>); |
653 | } | 683 | } |
654 | "#, | 684 | "#, |
655 | expect![[r#" | 685 | expect![[""]], |
656 | empty macro | ||
657 | ------ | ||
658 | foo!() | ||
659 | () | ||
660 | "#]], | ||
661 | ); | 686 | ); |
662 | } | 687 | } |
663 | 688 | ||
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index a610fd6d1..90f5b1c25 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -43,7 +43,7 @@ use crate::{ | |||
43 | completion::{ | 43 | completion::{ |
44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
45 | }, | 45 | }, |
46 | display::FunctionSignature, | 46 | display::function_signature::FunctionSignature, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 64349dcb8..e29b82017 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, |
12 | CompletionKind, Completions, | 12 | CompletionKind, Completions, |
13 | }, | 13 | }, |
14 | display::{const_label, macro_label, type_label, FunctionSignature}, | 14 | display::{const_label, function_signature::FunctionSignature, macro_label, type_label}, |
15 | CompletionScore, RootDatabase, | 15 | CompletionScore, RootDatabase, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -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.rs b/crates/ra_ide/src/display.rs index 70d2a2dd1..1ec946369 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -1,9 +1,8 @@ | |||
1 | //! This module contains utilities for turning SyntaxNodes and HIR types | 1 | //! This module contains utilities for turning SyntaxNodes and HIR types |
2 | //! into types that may be used to render in a UI. | 2 | //! into types that may be used to render in a UI. |
3 | 3 | ||
4 | mod function_signature; | 4 | pub(crate) mod function_signature; |
5 | mod navigation_target; | 5 | mod navigation_target; |
6 | mod structure; | ||
7 | mod short_label; | 6 | mod short_label; |
8 | 7 | ||
9 | use ra_syntax::{ | 8 | use ra_syntax::{ |
@@ -11,15 +10,13 @@ use ra_syntax::{ | |||
11 | SyntaxKind::{ATTR, COMMENT}, | 10 | SyntaxKind::{ATTR, COMMENT}, |
12 | }; | 11 | }; |
13 | 12 | ||
14 | pub use function_signature::FunctionSignature; | ||
15 | pub use navigation_target::NavigationTarget; | ||
16 | pub use structure::{file_structure, StructureNode}; | ||
17 | |||
18 | pub(crate) use navigation_target::{ToNav, TryToNav}; | 13 | pub(crate) use navigation_target::{ToNav, TryToNav}; |
19 | pub(crate) use short_label::ShortLabel; | 14 | pub(crate) use short_label::ShortLabel; |
20 | 15 | ||
16 | pub use navigation_target::NavigationTarget; | ||
17 | |||
21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 18 | pub(crate) fn function_label(node: &ast::FnDef) -> String { |
22 | FunctionSignature::from(node).to_string() | 19 | function_signature::FunctionSignature::from(node).to_string() |
23 | } | 20 | } |
24 | 21 | ||
25 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { | 22 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { |
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index 1d39544d3..9b7220d1f 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -15,49 +15,48 @@ use stdx::{split_delim, SepBy}; | |||
15 | use crate::display::{generic_parameters, where_predicates}; | 15 | use crate::display::{generic_parameters, where_predicates}; |
16 | 16 | ||
17 | #[derive(Debug)] | 17 | #[derive(Debug)] |
18 | pub enum CallableKind { | 18 | pub(crate) enum CallableKind { |
19 | Function, | 19 | Function, |
20 | StructConstructor, | 20 | StructConstructor, |
21 | VariantConstructor, | 21 | VariantConstructor, |
22 | Macro, | ||
23 | } | 22 | } |
24 | 23 | ||
25 | /// Contains information about a function signature | 24 | /// Contains information about a function signature |
26 | #[derive(Debug)] | 25 | #[derive(Debug)] |
27 | pub struct FunctionSignature { | 26 | pub(crate) struct FunctionSignature { |
28 | pub kind: CallableKind, | 27 | pub(crate) kind: CallableKind, |
29 | /// Optional visibility | 28 | /// Optional visibility |
30 | pub visibility: Option<String>, | 29 | pub(crate) visibility: Option<String>, |
31 | /// Qualifiers like `async`, `unsafe`, ... | 30 | /// Qualifiers like `async`, `unsafe`, ... |
32 | pub qualifier: FunctionQualifier, | 31 | pub(crate) qualifier: FunctionQualifier, |
33 | /// Name of the function | 32 | /// Name of the function |
34 | pub name: Option<String>, | 33 | pub(crate) name: Option<String>, |
35 | /// Documentation for the function | 34 | /// Documentation for the function |
36 | pub doc: Option<Documentation>, | 35 | pub(crate) doc: Option<Documentation>, |
37 | /// Generic parameters | 36 | /// Generic parameters |
38 | pub generic_parameters: Vec<String>, | 37 | pub(crate) generic_parameters: Vec<String>, |
39 | /// Parameters of the function | 38 | /// Parameters of the function |
40 | pub parameters: Vec<String>, | 39 | pub(crate) parameters: Vec<String>, |
41 | /// Parameter names of the function | 40 | /// Parameter names of the function |
42 | pub parameter_names: Vec<String>, | 41 | pub(crate) parameter_names: Vec<String>, |
43 | /// Parameter types of the function | 42 | /// Parameter types of the function |
44 | pub parameter_types: Vec<String>, | 43 | pub(crate) parameter_types: Vec<String>, |
45 | /// Optional return type | 44 | /// Optional return type |
46 | pub ret_type: Option<String>, | 45 | pub(crate) ret_type: Option<String>, |
47 | /// Where predicates | 46 | /// Where predicates |
48 | pub where_predicates: Vec<String>, | 47 | pub(crate) where_predicates: Vec<String>, |
49 | /// Self param presence | 48 | /// Self param presence |
50 | pub has_self_param: bool, | 49 | pub(crate) has_self_param: bool, |
51 | } | 50 | } |
52 | 51 | ||
53 | #[derive(Debug, Default)] | 52 | #[derive(Debug, Default)] |
54 | pub struct FunctionQualifier { | 53 | pub(crate) struct FunctionQualifier { |
55 | // `async` and `const` are mutually exclusive. Do we need to enforcing it here? | 54 | // `async` and `const` are mutually exclusive. Do we need to enforcing it here? |
56 | pub is_async: bool, | 55 | pub(crate) is_async: bool, |
57 | pub is_const: bool, | 56 | pub(crate) is_const: bool, |
58 | pub is_unsafe: bool, | 57 | pub(crate) is_unsafe: bool, |
59 | /// The string `extern ".."` | 58 | /// The string `extern ".."` |
60 | pub extern_abi: Option<String>, | 59 | pub(crate) extern_abi: Option<String>, |
61 | } | 60 | } |
62 | 61 | ||
63 | impl FunctionSignature { | 62 | impl FunctionSignature { |
@@ -149,27 +148,6 @@ impl FunctionSignature { | |||
149 | has_self_param: false, | 148 | has_self_param: false, |
150 | }) | 149 | }) |
151 | } | 150 | } |
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 | } | 151 | } |
174 | 152 | ||
175 | impl From<&'_ ast::FnDef> for FunctionSignature { | 153 | impl From<&'_ ast::FnDef> for FunctionSignature { |
@@ -298,7 +276,6 @@ impl Display for FunctionSignature { | |||
298 | CallableKind::Function => write!(f, "fn {}", name)?, | 276 | CallableKind::Function => write!(f, "fn {}", name)?, |
299 | CallableKind::StructConstructor => write!(f, "struct {}", name)?, | 277 | CallableKind::StructConstructor => write!(f, "struct {}", name)?, |
300 | CallableKind::VariantConstructor => write!(f, "{}", name)?, | 278 | CallableKind::VariantConstructor => write!(f, "{}", name)?, |
301 | CallableKind::Macro => write!(f, "{}!", name)?, | ||
302 | } | 279 | } |
303 | } | 280 | } |
304 | 281 | ||
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/file_structure.rs index 1f6a3febf..1f6a3febf 100644 --- a/crates/ra_ide/src/display/structure.rs +++ b/crates/ra_ide/src/file_structure.rs | |||
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 3cbae8a45..ae5695f61 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -5,10 +5,10 @@ use ra_syntax::{ | |||
5 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, | 5 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, |
6 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, | 6 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, |
7 | }; | 7 | }; |
8 | |||
9 | use crate::{FileId, FunctionSignature}; | ||
10 | use stdx::to_lower_snake_case; | 8 | use stdx::to_lower_snake_case; |
11 | 9 | ||
10 | use crate::{display::function_signature::FunctionSignature, FileId}; | ||
11 | |||
12 | #[derive(Clone, Debug, PartialEq, Eq)] | 12 | #[derive(Clone, Debug, PartialEq, Eq)] |
13 | pub struct InlayHintsConfig { | 13 | pub struct InlayHintsConfig { |
14 | pub type_hints: bool, | 14 | pub type_hints: bool, |
@@ -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/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 5d1f64e19..d3b20f371 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -19,29 +19,31 @@ pub mod mock_analysis; | |||
19 | 19 | ||
20 | mod markup; | 20 | mod markup; |
21 | mod prime_caches; | 21 | mod prime_caches; |
22 | mod status; | 22 | mod display; |
23 | |||
24 | mod call_hierarchy; | ||
25 | mod call_info; | ||
23 | mod completion; | 26 | mod completion; |
24 | mod runnables; | 27 | mod diagnostics; |
28 | mod expand_macro; | ||
29 | mod extend_selection; | ||
30 | mod file_structure; | ||
31 | mod folding_ranges; | ||
25 | mod goto_definition; | 32 | mod goto_definition; |
26 | mod goto_type_definition; | ||
27 | mod goto_implementation; | 33 | mod goto_implementation; |
28 | mod extend_selection; | 34 | mod goto_type_definition; |
29 | mod hover; | 35 | mod hover; |
30 | mod call_hierarchy; | 36 | mod inlay_hints; |
31 | mod call_info; | 37 | mod join_lines; |
32 | mod syntax_highlighting; | 38 | mod matching_brace; |
33 | mod parent_module; | 39 | mod parent_module; |
34 | mod references; | 40 | mod references; |
35 | mod diagnostics; | 41 | mod runnables; |
42 | mod ssr; | ||
43 | mod status; | ||
44 | mod syntax_highlighting; | ||
36 | mod syntax_tree; | 45 | mod syntax_tree; |
37 | mod folding_ranges; | ||
38 | mod join_lines; | ||
39 | mod typing; | 46 | mod typing; |
40 | mod matching_brace; | ||
41 | mod display; | ||
42 | mod inlay_hints; | ||
43 | mod expand_macro; | ||
44 | mod ssr; | ||
45 | 47 | ||
46 | use std::sync::Arc; | 48 | use std::sync::Arc; |
47 | 49 | ||
@@ -65,8 +67,9 @@ pub use crate::{ | |||
65 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, | 67 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, |
66 | }, | 68 | }, |
67 | diagnostics::Severity, | 69 | diagnostics::Severity, |
68 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, | 70 | display::NavigationTarget, |
69 | expand_macro::ExpandedMacro, | 71 | expand_macro::ExpandedMacro, |
72 | file_structure::StructureNode, | ||
70 | folding_ranges::{Fold, FoldKind}, | 73 | folding_ranges::{Fold, FoldKind}, |
71 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, | 74 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, |
72 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, | 75 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
@@ -323,7 +326,7 @@ impl Analysis { | |||
323 | /// Returns a tree representation of symbols in the file. Useful to draw a | 326 | /// Returns a tree representation of symbols in the file. Useful to draw a |
324 | /// file outline. | 327 | /// file outline. |
325 | pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> { | 328 | pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> { |
326 | self.with_db(|db| file_structure(&db.parse(file_id).tree())) | 329 | self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree())) |
327 | } | 330 | } |
328 | 331 | ||
329 | /// Returns a list of the places in the file where type hints can be displayed. | 332 | /// Returns a list of the places in the file where type hints can be displayed. |
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index 6863f100b..753001949 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs | |||
@@ -10,7 +10,7 @@ mod ssr; | |||
10 | use std::io::Read; | 10 | use std::io::Read; |
11 | 11 | ||
12 | use anyhow::Result; | 12 | use anyhow::Result; |
13 | use ra_ide::{file_structure, Analysis}; | 13 | use ra_ide::Analysis; |
14 | use ra_prof::profile; | 14 | use ra_prof::profile; |
15 | use ra_syntax::{AstNode, SourceFile}; | 15 | use ra_syntax::{AstNode, SourceFile}; |
16 | 16 | ||
@@ -48,8 +48,10 @@ pub fn parse(no_dump: bool) -> Result<()> { | |||
48 | } | 48 | } |
49 | 49 | ||
50 | pub fn symbols() -> Result<()> { | 50 | pub fn symbols() -> Result<()> { |
51 | let file = file()?; | 51 | let text = read_stdin()?; |
52 | for s in file_structure(&file) { | 52 | let (analysis, file_id) = Analysis::from_single_file(text); |
53 | let structure = analysis.file_structure(file_id).unwrap(); | ||
54 | for s in structure { | ||
53 | println!("{:?}", s); | 55 | println!("{:?}", s); |
54 | } | 56 | } |
55 | Ok(()) | 57 | Ok(()) |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index ed5e52871..68b2a2abd 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -127,6 +127,7 @@ pub struct ClientCapsConfig { | |||
127 | pub resolve_code_action: bool, | 127 | pub resolve_code_action: bool, |
128 | pub hover_actions: bool, | 128 | pub hover_actions: bool, |
129 | pub status_notification: bool, | 129 | pub status_notification: bool, |
130 | pub signature_help_label_offsets: bool, | ||
130 | } | 131 | } |
131 | 132 | ||
132 | impl Config { | 133 | impl Config { |
@@ -302,6 +303,15 @@ impl Config { | |||
302 | { | 303 | { |
303 | self.client_caps.code_action_literals = value; | 304 | self.client_caps.code_action_literals = value; |
304 | } | 305 | } |
306 | if let Some(value) = doc_caps | ||
307 | .signature_help | ||
308 | .as_ref() | ||
309 | .and_then(|it| it.signature_information.as_ref()) | ||
310 | .and_then(|it| it.parameter_information.as_ref()) | ||
311 | .and_then(|it| it.label_offset_support) | ||
312 | { | ||
313 | self.client_caps.signature_help_label_offsets = value; | ||
314 | } | ||
305 | 315 | ||
306 | self.completion.allow_snippets(false); | 316 | self.completion.allow_snippets(false); |
307 | if let Some(completion) = &doc_caps.completion { | 317 | if let Some(completion) = &doc_caps.completion { |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d28c700f1..18d660f42 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -553,21 +553,16 @@ 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( |
561 | if concise && call_info.signature.has_self_param { | 561 | call_info, |
562 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); | 562 | concise, |
563 | } | 563 | snap.config.client_caps.signature_help_label_offsets, |
564 | let sig_info = to_proto::signature_information(call_info.signature, concise); | 564 | ); |
565 | 565 | Ok(Some(res)) | |
566 | Ok(Some(lsp_types::SignatureHelp { | ||
567 | signatures: vec![sig_info], | ||
568 | active_signature: Some(0), | ||
569 | active_parameter, | ||
570 | })) | ||
571 | } | 566 | } |
572 | 567 | ||
573 | pub(crate) fn handle_hover( | 568 | 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..7fcb43a4f 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,72 @@ 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( |
223 | signature: FunctionSignature, | 223 | call_info: CallInfo, |
224 | concise: bool, | 224 | concise: bool, |
225 | ) -> lsp_types::SignatureInformation { | 225 | label_offsets: bool, |
226 | let (label, documentation, params) = if concise { | 226 | ) -> lsp_types::SignatureHelp { |
227 | let mut params = signature.parameters; | 227 | let (label, parameters) = match (concise, label_offsets) { |
228 | if signature.has_self_param { | 228 | (_, false) => { |
229 | params.remove(0); | 229 | let params = call_info |
230 | .parameter_labels() | ||
231 | .map(|label| lsp_types::ParameterInformation { | ||
232 | label: lsp_types::ParameterLabel::Simple(label.to_string()), | ||
233 | documentation: None, | ||
234 | }) | ||
235 | .collect::<Vec<_>>(); | ||
236 | let label = | ||
237 | if concise { call_info.parameter_labels().join(", ") } else { call_info.signature }; | ||
238 | (label, params) | ||
239 | } | ||
240 | (false, true) => { | ||
241 | let params = call_info | ||
242 | .parameter_ranges() | ||
243 | .iter() | ||
244 | .map(|it| [u32::from(it.start()).into(), u32::from(it.end()).into()]) | ||
245 | .map(|label_offsets| lsp_types::ParameterInformation { | ||
246 | label: lsp_types::ParameterLabel::LabelOffsets(label_offsets), | ||
247 | documentation: None, | ||
248 | }) | ||
249 | .collect::<Vec<_>>(); | ||
250 | (call_info.signature, params) | ||
251 | } | ||
252 | (true, true) => { | ||
253 | let mut params = Vec::new(); | ||
254 | let mut label = String::new(); | ||
255 | let mut first = true; | ||
256 | for param in call_info.parameter_labels() { | ||
257 | if !first { | ||
258 | label.push_str(", "); | ||
259 | } | ||
260 | first = false; | ||
261 | let start = label.len() as u64; | ||
262 | label.push_str(param); | ||
263 | let end = label.len() as u64; | ||
264 | params.push(lsp_types::ParameterInformation { | ||
265 | label: lsp_types::ParameterLabel::LabelOffsets([start, end]), | ||
266 | documentation: None, | ||
267 | }); | ||
268 | } | ||
269 | |||
270 | (label, params) | ||
230 | } | 271 | } |
231 | (params.join(", "), None, params) | ||
232 | } else { | ||
233 | (signature.to_string(), signature.doc.map(documentation), signature.parameters) | ||
234 | }; | 272 | }; |
235 | 273 | ||
236 | let parameters: Vec<lsp_types::ParameterInformation> = params | 274 | let documentation = call_info.doc.map(|doc| { |
237 | .into_iter() | 275 | lsp_types::Documentation::MarkupContent(lsp_types::MarkupContent { |
238 | .map(|param| lsp_types::ParameterInformation { | 276 | kind: lsp_types::MarkupKind::Markdown, |
239 | label: lsp_types::ParameterLabel::Simple(param), | 277 | value: doc, |
240 | documentation: None, | ||
241 | }) | 278 | }) |
242 | .collect(); | 279 | }); |
243 | 280 | ||
244 | lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) } | 281 | let signature = |
282 | lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) }; | ||
283 | lsp_types::SignatureHelp { | ||
284 | signatures: vec![signature], | ||
285 | active_signature: None, | ||
286 | active_parameter: call_info.active_parameter.map(|it| it as i64), | ||
287 | } | ||
245 | } | 288 | } |
246 | 289 | ||
247 | pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { | 290 | pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { |