diff options
32 files changed, 821 insertions, 886 deletions
diff --git a/Cargo.lock b/Cargo.lock index cde82397c..451ba1f42 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -709,9 +709,9 @@ dependencies = [ | |||
709 | 709 | ||
710 | [[package]] | 710 | [[package]] |
711 | name = "log" | 711 | name = "log" |
712 | version = "0.4.8" | 712 | version = "0.4.11" |
713 | source = "registry+https://github.com/rust-lang/crates.io-index" | 713 | source = "registry+https://github.com/rust-lang/crates.io-index" |
714 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" | 714 | checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" |
715 | dependencies = [ | 715 | dependencies = [ |
716 | "cfg-if", | 716 | "cfg-if", |
717 | ] | 717 | ] |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 9891b0785..859bdfb3b 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,14 @@ 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 def = match self.ty.value { |
1230 | Some(self.ty.value.as_callable()?.0) | 1237 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def), |
1238 | _ => None, | ||
1239 | }; | ||
1240 | |||
1241 | let sig = self.ty.value.callable_sig(db)?; | ||
1242 | Some(Callable { ty: self.clone(), sig, def, is_bound_method: false }) | ||
1231 | } | 1243 | } |
1232 | 1244 | ||
1233 | pub fn is_closure(&self) -> bool { | 1245 | pub fn is_closure(&self) -> bool { |
@@ -1512,6 +1524,74 @@ impl HirDisplay for Type { | |||
1512 | } | 1524 | } |
1513 | } | 1525 | } |
1514 | 1526 | ||
1527 | // FIXME: closures | ||
1528 | #[derive(Debug)] | ||
1529 | pub struct Callable { | ||
1530 | ty: Type, | ||
1531 | sig: FnSig, | ||
1532 | def: Option<CallableDefId>, | ||
1533 | pub(crate) is_bound_method: bool, | ||
1534 | } | ||
1535 | |||
1536 | pub enum CallableKind { | ||
1537 | Function(Function), | ||
1538 | TupleStruct(Struct), | ||
1539 | TupleEnumVariant(EnumVariant), | ||
1540 | Closure, | ||
1541 | } | ||
1542 | |||
1543 | impl Callable { | ||
1544 | pub fn kind(&self) -> CallableKind { | ||
1545 | match self.def { | ||
1546 | Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), | ||
1547 | Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), | ||
1548 | Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()), | ||
1549 | None => CallableKind::Closure, | ||
1550 | } | ||
1551 | } | ||
1552 | pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { | ||
1553 | let func = match self.def { | ||
1554 | Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it, | ||
1555 | _ => return None, | ||
1556 | }; | ||
1557 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
1558 | let param_list = src.value.param_list()?; | ||
1559 | param_list.self_param() | ||
1560 | } | ||
1561 | pub fn n_params(&self) -> usize { | ||
1562 | self.sig.params().len() - if self.is_bound_method { 1 } else { 0 } | ||
1563 | } | ||
1564 | pub fn params( | ||
1565 | &self, | ||
1566 | db: &dyn HirDatabase, | ||
1567 | ) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> { | ||
1568 | let types = self | ||
1569 | .sig | ||
1570 | .params() | ||
1571 | .iter() | ||
1572 | .skip(if self.is_bound_method { 1 } else { 0 }) | ||
1573 | .map(|ty| self.ty.derived(ty.clone())); | ||
1574 | let patterns = match self.def { | ||
1575 | Some(CallableDefId::FunctionId(func)) => { | ||
1576 | let src = func.lookup(db.upcast()).source(db.upcast()); | ||
1577 | src.value.param_list().map(|param_list| { | ||
1578 | param_list | ||
1579 | .self_param() | ||
1580 | .map(|it| Some(Either::Left(it))) | ||
1581 | .filter(|_| !self.is_bound_method) | ||
1582 | .into_iter() | ||
1583 | .chain(param_list.params().map(|it| it.pat().map(Either::Right))) | ||
1584 | }) | ||
1585 | } | ||
1586 | _ => None, | ||
1587 | }; | ||
1588 | patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() | ||
1589 | } | ||
1590 | pub fn return_type(&self) -> Type { | ||
1591 | self.ty.derived(self.sig.ret().clone()) | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1515 | /// For IDE only | 1595 | /// For IDE only |
1516 | #[derive(Debug)] | 1596 | #[derive(Debug)] |
1517 | pub enum ScopeDef { | 1597 | 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_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs index 557d01cdc..fd930eab1 100644 --- a/crates/ra_hir_ty/src/diagnostics/expr.rs +++ b/crates/ra_hir_ty/src/diagnostics/expr.rs | |||
@@ -158,28 +158,32 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
158 | } | 158 | } |
159 | 159 | ||
160 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | 160 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); |
161 | let (callee, args) = match expr { | 161 | let (sig, args) = match expr { |
162 | Expr::Call { callee, args } => { | 162 | Expr::Call { callee, args } => { |
163 | let callee = &self.infer.type_of_expr[*callee]; | 163 | let callee = &self.infer.type_of_expr[*callee]; |
164 | let (callable, _) = callee.as_callable()?; | 164 | let sig = callee.callable_sig(db)?; |
165 | 165 | (sig, args.clone()) | |
166 | (callable, args.clone()) | ||
167 | } | 166 | } |
168 | Expr::MethodCall { receiver, args, .. } => { | 167 | Expr::MethodCall { receiver, args, .. } => { |
169 | let callee = self.infer.method_resolution(call_id)?; | ||
170 | let mut args = args.clone(); | 168 | let mut args = args.clone(); |
171 | args.insert(0, *receiver); | 169 | args.insert(0, *receiver); |
172 | (callee.into(), args) | 170 | |
171 | // FIXME: note that we erase information about substs here. This | ||
172 | // is not right, but, luckily, doesn't matter as we care only | ||
173 | // about the number of params | ||
174 | let callee = self.infer.method_resolution(call_id)?; | ||
175 | let sig = db.callable_item_signature(callee.into()).value; | ||
176 | |||
177 | (sig, args) | ||
173 | } | 178 | } |
174 | _ => return None, | 179 | _ => return None, |
175 | }; | 180 | }; |
176 | 181 | ||
177 | let sig = db.callable_item_signature(callee); | 182 | if sig.is_varargs { |
178 | if sig.value.is_varargs { | ||
179 | return None; | 183 | return None; |
180 | } | 184 | } |
181 | 185 | ||
182 | let params = sig.value.params(); | 186 | let params = sig.params(); |
183 | 187 | ||
184 | let mut param_count = params.len(); | 188 | let mut param_count = params.len(); |
185 | let mut arg_count = args.len(); | 189 | let mut arg_count = args.len(); |
@@ -542,4 +546,20 @@ fn f() { | |||
542 | "#, | 546 | "#, |
543 | ) | 547 | ) |
544 | } | 548 | } |
549 | |||
550 | #[test] | ||
551 | fn arg_count_lambda() { | ||
552 | check_diagnostics( | ||
553 | r#" | ||
554 | fn main() { | ||
555 | let f = |()| (); | ||
556 | f(); | ||
557 | //^^^ Expected 1 argument, found 0 | ||
558 | f(()); | ||
559 | f((), ()); | ||
560 | //^^^^^^^^^ Expected 1 argument, found 2 | ||
561 | } | ||
562 | "#, | ||
563 | ) | ||
564 | } | ||
545 | } | 565 | } |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 0ef5ca78f..7698cb0d4 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -767,15 +767,6 @@ impl Ty { | |||
767 | } | 767 | } |
768 | } | 768 | } |
769 | 769 | ||
770 | pub fn as_callable(&self) -> Option<(CallableDefId, &Substs)> { | ||
771 | match self { | ||
772 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => { | ||
773 | Some((*callable_def, parameters)) | ||
774 | } | ||
775 | _ => None, | ||
776 | } | ||
777 | } | ||
778 | |||
779 | pub fn is_never(&self) -> bool { | 770 | pub fn is_never(&self) -> bool { |
780 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) | 771 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) |
781 | } | 772 | } |
@@ -807,7 +798,7 @@ impl Ty { | |||
807 | } | 798 | } |
808 | } | 799 | } |
809 | 800 | ||
810 | fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { | 801 | pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { |
811 | match self { | 802 | match self { |
812 | Ty::Apply(a_ty) => match a_ty.ctor { | 803 | Ty::Apply(a_ty) => match a_ty.ctor { |
813 | TypeCtor::FnPtr { is_varargs, .. } => { | 804 | TypeCtor::FnPtr { is_varargs, .. } => { |
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs index cb7e62cd6..c28af8ab3 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 { |
@@ -158,7 +154,8 @@ mod tests { | |||
158 | let nav = navs.pop().unwrap(); | 154 | let nav = navs.pop().unwrap(); |
159 | nav.assert_match(expected); | 155 | nav.assert_match(expected); |
160 | 156 | ||
161 | let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() }; | 157 | let item_pos = |
158 | FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() }; | ||
162 | let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); | 159 | let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); |
163 | assert_eq!(incoming_calls.len(), expected_incoming.len()); | 160 | assert_eq!(incoming_calls.len(), expected_incoming.len()); |
164 | 161 | ||
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index 1fe1c21de..14980afdd 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,131 @@ 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 | } | ||
73 | hir::CallableKind::Closure => (), | ||
40 | } | 74 | } |
41 | 75 | ||
42 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { | 76 | res.signature.push('('); |
43 | call_info_for_token(sema, token)?.into_active_parameter() | 77 | { |
78 | if let Some(self_param) = callable.receiver_param(db) { | ||
79 | format_to!(res.signature, "{}", self_param) | ||
80 | } | ||
81 | let mut buf = String::new(); | ||
82 | for (pat, ty) in callable.params(db) { | ||
83 | buf.clear(); | ||
84 | if let Some(pat) = pat { | ||
85 | match pat { | ||
86 | Either::Left(_self) => format_to!(buf, "self: "), | ||
87 | Either::Right(pat) => format_to!(buf, "{}: ", pat), | ||
88 | } | ||
89 | } | ||
90 | format_to!(buf, "{}", ty.display(db)); | ||
91 | res.push_param(&buf); | ||
92 | } | ||
44 | } | 93 | } |
94 | res.signature.push(')'); | ||
95 | |||
96 | match callable.kind() { | ||
97 | hir::CallableKind::Function(_) | hir::CallableKind::Closure => { | ||
98 | let ret_type = callable.return_type(); | ||
99 | if !ret_type.is_unit() { | ||
100 | format_to!(res.signature, " -> {}", ret_type.display(db)); | ||
101 | } | ||
102 | } | ||
103 | hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} | ||
104 | } | ||
105 | Some(res) | ||
45 | } | 106 | } |
46 | 107 | ||
47 | fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { | 108 | fn call_info_impl( |
109 | sema: &Semantics<RootDatabase>, | ||
110 | token: SyntaxToken, | ||
111 | ) -> Option<(hir::Callable, Option<usize>)> { | ||
48 | // Find the calling expression and it's NameRef | 112 | // Find the calling expression and it's NameRef |
49 | let calling_node = FnCallNode::with_node(&token.parent())?; | 113 | let calling_node = FnCallNode::with_node(&token.parent())?; |
50 | 114 | ||
51 | let signature = match &calling_node { | 115 | let callable = match &calling_node { |
52 | FnCallNode::CallExpr(call) => { | 116 | FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?, |
53 | //FIXME: Type::as_callable is broken | 117 | FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?, |
54 | let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; | 118 | }; |
55 | match callable_def { | 119 | let active_param = if let Some(arg_list) = calling_node.arg_list() { |
56 | hir::CallableDefId::FunctionId(it) => { | 120 | // Number of arguments specified at the call site |
57 | let fn_def = it.into(); | 121 | let num_args_at_callsite = arg_list.args().count(); |
58 | FunctionSignature::from_hir(sema.db, fn_def) | 122 | |
59 | } | 123 | let arg_list_range = arg_list.syntax().text_range(); |
60 | hir::CallableDefId::StructId(it) => { | 124 | if !arg_list_range.contains_inclusive(token.text_range().start()) { |
61 | FunctionSignature::from_struct(sema.db, it.into())? | 125 | mark::hit!(call_info_bad_offset); |
62 | } | 126 | 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 | } | 127 | } |
128 | let param = std::cmp::min( | ||
129 | num_args_at_callsite, | ||
130 | arg_list | ||
131 | .args() | ||
132 | .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) | ||
133 | .count(), | ||
134 | ); | ||
135 | |||
136 | Some(param) | ||
137 | } else { | ||
138 | None | ||
76 | }; | 139 | }; |
140 | Some((callable, active_param)) | ||
141 | } | ||
77 | 142 | ||
78 | // If we have a calling expression let's find which argument we are on | 143 | #[derive(Debug)] |
79 | let num_params = signature.parameters.len(); | 144 | pub(crate) struct ActiveParameter { |
80 | 145 | pub(crate) ty: Type, | |
81 | let active_parameter = match num_params { | 146 | pub(crate) name: String, |
82 | 0 => None, | 147 | } |
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 | 148 | ||
96 | let mut param = std::cmp::min( | 149 | impl ActiveParameter { |
97 | num_args_at_callsite, | 150 | pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { |
98 | arg_list | 151 | let sema = Semantics::new(db); |
99 | .args() | 152 | let file = sema.parse(position.file_id); |
100 | .take_while(|arg| { | 153 | let file = file.syntax(); |
101 | arg.syntax().text_range().end() <= token.text_range().start() | 154 | let token = file.token_at_offset(position.offset).next()?; |
102 | }) | 155 | let token = sema.descend_into_macros(token); |
103 | .count(), | 156 | Self::at_token(&sema, token) |
104 | ); | 157 | } |
105 | |||
106 | // If we are in a method account for `self` | ||
107 | if signature.has_self_param { | ||
108 | param += 1; | ||
109 | } | ||
110 | 158 | ||
111 | Some(param) | 159 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { |
112 | } else { | 160 | let (signature, active_parameter) = call_info_impl(&sema, token)?; |
113 | None | ||
114 | } | ||
115 | } | ||
116 | }; | ||
117 | 161 | ||
118 | Some(CallInfo { signature, active_parameter }) | 162 | let idx = active_parameter?; |
163 | let mut params = signature.params(sema.db); | ||
164 | let (pat, ty) = params.swap_remove(idx); | ||
165 | let name = pat?.to_string(); | ||
166 | Some(ActiveParameter { ty, name }) | ||
167 | } | ||
119 | } | 168 | } |
120 | 169 | ||
121 | #[derive(Debug)] | 170 | #[derive(Debug)] |
122 | pub(crate) enum FnCallNode { | 171 | pub(crate) enum FnCallNode { |
123 | CallExpr(ast::CallExpr), | 172 | CallExpr(ast::CallExpr), |
124 | MethodCallExpr(ast::MethodCallExpr), | 173 | MethodCallExpr(ast::MethodCallExpr), |
125 | MacroCallExpr(ast::MacroCall), | ||
126 | } | 174 | } |
127 | 175 | ||
128 | impl FnCallNode { | 176 | impl FnCallNode { |
@@ -138,7 +186,6 @@ impl FnCallNode { | |||
138 | } | 186 | } |
139 | Some(FnCallNode::MethodCallExpr(it)) | 187 | Some(FnCallNode::MethodCallExpr(it)) |
140 | }, | 188 | }, |
141 | ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)), | ||
142 | _ => None, | 189 | _ => None, |
143 | } | 190 | } |
144 | } | 191 | } |
@@ -150,7 +197,6 @@ impl FnCallNode { | |||
150 | match node { | 197 | match node { |
151 | ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), | 198 | ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), |
152 | ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), | 199 | ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), |
153 | ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)), | ||
154 | _ => None, | 200 | _ => None, |
155 | } | 201 | } |
156 | } | 202 | } |
@@ -166,8 +212,6 @@ impl FnCallNode { | |||
166 | FnCallNode::MethodCallExpr(call_expr) => { | 212 | FnCallNode::MethodCallExpr(call_expr) => { |
167 | call_expr.syntax().children().filter_map(ast::NameRef::cast).next() | 213 | call_expr.syntax().children().filter_map(ast::NameRef::cast).next() |
168 | } | 214 | } |
169 | |||
170 | FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(), | ||
171 | } | 215 | } |
172 | } | 216 | } |
173 | 217 | ||
@@ -175,21 +219,10 @@ impl FnCallNode { | |||
175 | match self { | 219 | match self { |
176 | FnCallNode::CallExpr(expr) => expr.arg_list(), | 220 | FnCallNode::CallExpr(expr) => expr.arg_list(), |
177 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), | 221 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), |
178 | FnCallNode::MacroCallExpr(_) => None, | ||
179 | } | 222 | } |
180 | } | 223 | } |
181 | } | 224 | } |
182 | 225 | ||
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)] | 226 | #[cfg(test)] |
194 | mod tests { | 227 | mod tests { |
195 | use expect::{expect, Expect}; | 228 | use expect::{expect, Expect}; |
@@ -202,20 +235,18 @@ mod tests { | |||
202 | let call_info = analysis.call_info(position).unwrap(); | 235 | let call_info = analysis.call_info(position).unwrap(); |
203 | let actual = match call_info { | 236 | let actual = match call_info { |
204 | Some(call_info) => { | 237 | Some(call_info) => { |
205 | let docs = match &call_info.signature.doc { | 238 | let docs = match &call_info.doc { |
206 | None => "".to_string(), | 239 | None => "".to_string(), |
207 | Some(docs) => format!("{}\n------\n", docs.as_str()), | 240 | Some(docs) => format!("{}\n------\n", docs.as_str()), |
208 | }; | 241 | }; |
209 | let params = call_info | 242 | let params = call_info |
210 | .signature | 243 | .parameter_labels() |
211 | .parameters | ||
212 | .iter() | ||
213 | .enumerate() | 244 | .enumerate() |
214 | .map(|(i, param)| { | 245 | .map(|(i, param)| { |
215 | if Some(i) == call_info.active_parameter { | 246 | if Some(i) == call_info.active_parameter { |
216 | format!("<{}>", param) | 247 | format!("<{}>", param) |
217 | } else { | 248 | } else { |
218 | param.clone() | 249 | param.to_string() |
219 | } | 250 | } |
220 | }) | 251 | }) |
221 | .collect::<Vec<_>>() | 252 | .collect::<Vec<_>>() |
@@ -296,10 +327,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | |||
296 | fn bar() { foo(<|>3, ); } | 327 | fn bar() { foo(<|>3, ); } |
297 | "#, | 328 | "#, |
298 | expect![[r#" | 329 | expect![[r#" |
299 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | 330 | fn foo(x: i32, y: {unknown}) -> u32 |
300 | where T: Copy + Display, | 331 | (<x: i32>, y: {unknown}) |
301 | U: Debug | ||
302 | (<x: T>, y: U) | ||
303 | "#]], | 332 | "#]], |
304 | ); | 333 | ); |
305 | } | 334 | } |
@@ -312,8 +341,7 @@ fn foo<T>() -> T where T: Copy + Display {} | |||
312 | fn bar() { foo(<|>); } | 341 | fn bar() { foo(<|>); } |
313 | "#, | 342 | "#, |
314 | expect![[r#" | 343 | expect![[r#" |
315 | fn foo<T>() -> T | 344 | fn foo() -> {unknown} |
316 | where T: Copy + Display | ||
317 | () | 345 | () |
318 | "#]], | 346 | "#]], |
319 | ); | 347 | ); |
@@ -323,11 +351,14 @@ fn bar() { foo(<|>); } | |||
323 | fn test_fn_signature_for_impl() { | 351 | fn test_fn_signature_for_impl() { |
324 | check( | 352 | check( |
325 | r#" | 353 | r#" |
326 | struct F; impl F { pub fn new() { F{}} } | 354 | struct F; |
327 | fn bar() {let _ : F = F::new(<|>);} | 355 | impl F { pub fn new() { } } |
356 | fn bar() { | ||
357 | let _ : F = F::new(<|>); | ||
358 | } | ||
328 | "#, | 359 | "#, |
329 | expect![[r#" | 360 | expect![[r#" |
330 | pub fn new() | 361 | fn new() |
331 | () | 362 | () |
332 | "#]], | 363 | "#]], |
333 | ); | 364 | ); |
@@ -346,8 +377,8 @@ fn bar() { | |||
346 | } | 377 | } |
347 | "#, | 378 | "#, |
348 | expect![[r#" | 379 | expect![[r#" |
349 | pub fn do_it(&self) | 380 | fn do_it(&self) |
350 | (&self) | 381 | () |
351 | "#]], | 382 | "#]], |
352 | ); | 383 | ); |
353 | } | 384 | } |
@@ -357,16 +388,33 @@ fn bar() { | |||
357 | check( | 388 | check( |
358 | r#" | 389 | r#" |
359 | struct S; | 390 | struct S; |
360 | impl S { pub fn do_it(&self, x: i32) {} } | 391 | impl S { |
392 | fn foo(&self, x: i32) {} | ||
393 | } | ||
361 | 394 | ||
362 | fn bar() { | 395 | fn main() { S.foo(<|>); } |
363 | let s: S = S; | 396 | "#, |
364 | s.do_it(<|>); | 397 | expect![[r#" |
398 | fn foo(&self, x: i32) | ||
399 | (<x: i32>) | ||
400 | "#]], | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { | ||
406 | check( | ||
407 | r#" | ||
408 | struct S; | ||
409 | impl S { | ||
410 | fn foo(&self, x: i32) {} | ||
365 | } | 411 | } |
412 | |||
413 | fn main() { S::foo(<|>); } | ||
366 | "#, | 414 | "#, |
367 | expect![[r#" | 415 | expect![[r#" |
368 | pub fn do_it(&self, x: i32) | 416 | fn foo(self: &S, x: i32) |
369 | (&self, <x: i32>) | 417 | (<self: &S>, x: i32) |
370 | "#]], | 418 | "#]], |
371 | ); | 419 | ); |
372 | } | 420 | } |
@@ -425,7 +473,7 @@ pub fn do() { | |||
425 | assert_eq!(6, my_crate::add_one(5)); | 473 | assert_eq!(6, my_crate::add_one(5)); |
426 | ``` | 474 | ``` |
427 | ------ | 475 | ------ |
428 | pub fn add_one(x: i32) -> i32 | 476 | fn add_one(x: i32) -> i32 |
429 | (<x: i32>) | 477 | (<x: i32>) |
430 | "##]], | 478 | "##]], |
431 | ); | 479 | ); |
@@ -467,7 +515,7 @@ pub fn do_it() { | |||
467 | assert_eq!(6, my_crate::add_one(5)); | 515 | assert_eq!(6, my_crate::add_one(5)); |
468 | ``` | 516 | ``` |
469 | ------ | 517 | ------ |
470 | pub fn add_one(x: i32) -> i32 | 518 | fn add_one(x: i32) -> i32 |
471 | (<x: i32>) | 519 | (<x: i32>) |
472 | "##]], | 520 | "##]], |
473 | ); | 521 | ); |
@@ -505,8 +553,8 @@ pub fn foo(mut r: WriteHandler<()>) { | |||
505 | 553 | ||
506 | By default this method stops actor's `Context`. | 554 | By default this method stops actor's `Context`. |
507 | ------ | 555 | ------ |
508 | fn finished(&mut self, ctx: &mut Self::Context) | 556 | fn finished(&mut self, ctx: &mut {unknown}) |
509 | (&mut self, <ctx: &mut Self::Context>) | 557 | (<ctx: &mut {unknown}>) |
510 | "#]], | 558 | "#]], |
511 | ); | 559 | ); |
512 | } | 560 | } |
@@ -539,7 +587,7 @@ fn main() { | |||
539 | "#, | 587 | "#, |
540 | expect![[r#" | 588 | expect![[r#" |
541 | fn bar(&self, _: u32) | 589 | fn bar(&self, _: u32) |
542 | (&self, <_: u32>) | 590 | (<_: u32>) |
543 | "#]], | 591 | "#]], |
544 | ); | 592 | ); |
545 | } | 593 | } |
@@ -549,15 +597,15 @@ fn main() { | |||
549 | check( | 597 | check( |
550 | r#" | 598 | r#" |
551 | /// A cool tuple struct | 599 | /// A cool tuple struct |
552 | struct TS(u32, i32); | 600 | struct S(u32, i32); |
553 | fn main() { | 601 | fn main() { |
554 | let s = TS(0, <|>); | 602 | let s = S(0, <|>); |
555 | } | 603 | } |
556 | "#, | 604 | "#, |
557 | expect![[r#" | 605 | expect![[r#" |
558 | A cool tuple struct | 606 | A cool tuple struct |
559 | ------ | 607 | ------ |
560 | struct TS(u32, i32) -> TS | 608 | struct S(u32, i32) |
561 | (u32, <i32>) | 609 | (u32, <i32>) |
562 | "#]], | 610 | "#]], |
563 | ); | 611 | ); |
@@ -567,32 +615,19 @@ fn main() { | |||
567 | fn generic_struct() { | 615 | fn generic_struct() { |
568 | check( | 616 | check( |
569 | r#" | 617 | r#" |
570 | struct TS<T>(T); | 618 | struct S<T>(T); |
571 | fn main() { | 619 | fn main() { |
572 | let s = TS(<|>); | 620 | let s = S(<|>); |
573 | } | 621 | } |
574 | "#, | 622 | "#, |
575 | expect![[r#" | 623 | expect![[r#" |
576 | struct TS<T>(T) -> TS | 624 | struct S({unknown}) |
577 | (<T>) | 625 | (<{unknown}>) |
578 | "#]], | 626 | "#]], |
579 | ); | 627 | ); |
580 | } | 628 | } |
581 | 629 | ||
582 | #[test] | 630 | #[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() { | 631 | fn works_for_enum_variants() { |
597 | check( | 632 | check( |
598 | r#" | 633 | r#" |
@@ -612,14 +647,27 @@ fn main() { | |||
612 | expect![[r#" | 647 | expect![[r#" |
613 | A Variant | 648 | A Variant |
614 | ------ | 649 | ------ |
615 | E::A(0: i32) | 650 | enum E::A(i32) |
616 | (<0: i32>) | 651 | (<i32>) |
617 | "#]], | 652 | "#]], |
618 | ); | 653 | ); |
619 | } | 654 | } |
620 | 655 | ||
621 | #[test] | 656 | #[test] |
622 | fn cant_call_enum_records() { | 657 | fn cant_call_struct_record() { |
658 | check( | ||
659 | r#" | ||
660 | struct S { x: u32, y: i32 } | ||
661 | fn main() { | ||
662 | let s = S(<|>); | ||
663 | } | ||
664 | "#, | ||
665 | expect![[""]], | ||
666 | ); | ||
667 | } | ||
668 | |||
669 | #[test] | ||
670 | fn cant_call_enum_record() { | ||
623 | check( | 671 | check( |
624 | r#" | 672 | r#" |
625 | enum E { | 673 | enum E { |
@@ -640,41 +688,51 @@ fn main() { | |||
640 | } | 688 | } |
641 | 689 | ||
642 | #[test] | 690 | #[test] |
643 | fn fn_signature_for_macro() { | 691 | fn fn_signature_for_call_in_macro() { |
644 | check( | 692 | check( |
645 | r#" | 693 | r#" |
646 | /// empty macro | 694 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
647 | macro_rules! foo { | 695 | fn foo() { } |
648 | () => {} | 696 | id! { |
649 | } | 697 | fn bar() { foo(<|>); } |
650 | |||
651 | fn f() { | ||
652 | foo!(<|>); | ||
653 | } | 698 | } |
654 | "#, | 699 | "#, |
655 | expect![[r#" | 700 | expect![[r#" |
656 | empty macro | 701 | fn foo() |
657 | ------ | ||
658 | foo!() | ||
659 | () | 702 | () |
660 | "#]], | 703 | "#]], |
661 | ); | 704 | ); |
662 | } | 705 | } |
663 | 706 | ||
664 | #[test] | 707 | #[test] |
665 | fn fn_signature_for_call_in_macro() { | 708 | fn call_info_for_lambdas() { |
666 | check( | 709 | check( |
667 | r#" | 710 | r#" |
668 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 711 | struct S; |
669 | fn foo() { } | 712 | fn foo(s: S) -> i32 { 92 } |
670 | id! { | 713 | fn main() { |
671 | fn bar() { foo(<|>); } | 714 | (|s| foo(s))(<|>) |
672 | } | 715 | } |
673 | "#, | 716 | "#, |
674 | expect![[r#" | 717 | expect![[r#" |
675 | fn foo() | 718 | (S) -> i32 |
676 | () | 719 | (<S>) |
677 | "#]], | 720 | "#]], |
678 | ); | 721 | ) |
722 | } | ||
723 | |||
724 | #[test] | ||
725 | fn call_info_for_fn_ptr() { | ||
726 | check( | ||
727 | r#" | ||
728 | fn main(f: fn(i32, f64) -> char) { | ||
729 | f(0, <|>) | ||
730 | } | ||
731 | "#, | ||
732 | expect![[r#" | ||
733 | (i32, f64) -> char | ||
734 | (i32, <f64>) | ||
735 | "#]], | ||
736 | ) | ||
679 | } | 737 | } |
680 | } | 738 | } |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index a610fd6d1..cf716540f 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_declaration, |
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) { |
@@ -125,8 +125,6 @@ fn add_function_impl( | |||
125 | ctx: &CompletionContext, | 125 | ctx: &CompletionContext, |
126 | func: hir::Function, | 126 | func: hir::Function, |
127 | ) { | 127 | ) { |
128 | let signature = FunctionSignature::from_hir(ctx.db, func); | ||
129 | |||
130 | let fn_name = func.name(ctx.db).to_string(); | 128 | let fn_name = func.name(ctx.db).to_string(); |
131 | 129 | ||
132 | let label = if !func.params(ctx.db).is_empty() { | 130 | let label = if !func.params(ctx.db).is_empty() { |
@@ -146,13 +144,14 @@ fn add_function_impl( | |||
146 | }; | 144 | }; |
147 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 145 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); |
148 | 146 | ||
147 | let function_decl = function_declaration(&func.source(ctx.db).value); | ||
149 | match ctx.config.snippet_cap { | 148 | match ctx.config.snippet_cap { |
150 | Some(cap) => { | 149 | Some(cap) => { |
151 | let snippet = format!("{} {{\n $0\n}}", signature); | 150 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
152 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | 151 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) |
153 | } | 152 | } |
154 | None => { | 153 | None => { |
155 | let header = format!("{} {{", signature); | 154 | let header = format!("{} {{", function_decl); |
156 | builder.text_edit(TextEdit::replace(range, header)) | 155 | builder.text_edit(TextEdit::replace(range, header)) |
157 | } | 156 | } |
158 | } | 157 | } |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 64349dcb8..c7b74e635 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_declaration, macro_label, type_label}, |
15 | CompletionScore, RootDatabase, | 15 | CompletionScore, RootDatabase, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -195,7 +195,6 @@ impl Completions { | |||
195 | 195 | ||
196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); | 196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); |
197 | let ast_node = func.source(ctx.db).value; | 197 | let ast_node = func.source(ctx.db).value; |
198 | let function_signature = FunctionSignature::from(&ast_node); | ||
199 | 198 | ||
200 | let mut builder = | 199 | let mut builder = |
201 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) | 200 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) |
@@ -206,13 +205,14 @@ impl Completions { | |||
206 | }) | 205 | }) |
207 | .set_documentation(func.docs(ctx.db)) | 206 | .set_documentation(func.docs(ctx.db)) |
208 | .set_deprecated(is_deprecated(func, ctx.db)) | 207 | .set_deprecated(is_deprecated(func, ctx.db)) |
209 | .detail(function_signature.to_string()); | 208 | .detail(function_declaration(&ast_node)); |
210 | 209 | ||
211 | let params = function_signature | 210 | let params = ast_node |
212 | .parameter_names | 211 | .param_list() |
213 | .iter() | 212 | .into_iter() |
214 | .skip(if function_signature.has_self_param { 1 } else { 0 }) | 213 | .flat_map(|it| it.params()) |
215 | .map(|name| name.trim_start_matches('_').into()) | 214 | .flat_map(|it| it.pat()) |
215 | .map(|pat| pat.to_string().trim_start_matches('_').into()) | ||
216 | .collect(); | 216 | .collect(); |
217 | 217 | ||
218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); | 218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); |
@@ -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..6d4151dd8 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -1,9 +1,7 @@ | |||
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; | ||
5 | mod navigation_target; | 4 | mod navigation_target; |
6 | mod structure; | ||
7 | mod short_label; | 5 | mod short_label; |
8 | 6 | ||
9 | use ra_syntax::{ | 7 | use ra_syntax::{ |
@@ -11,15 +9,49 @@ use ra_syntax::{ | |||
11 | SyntaxKind::{ATTR, COMMENT}, | 9 | SyntaxKind::{ATTR, COMMENT}, |
12 | }; | 10 | }; |
13 | 11 | ||
14 | pub use function_signature::FunctionSignature; | 12 | use ast::VisibilityOwner; |
15 | pub use navigation_target::NavigationTarget; | 13 | use stdx::format_to; |
16 | pub use structure::{file_structure, StructureNode}; | ||
17 | 14 | ||
15 | pub use navigation_target::NavigationTarget; | ||
18 | pub(crate) use navigation_target::{ToNav, TryToNav}; | 16 | pub(crate) use navigation_target::{ToNav, TryToNav}; |
19 | pub(crate) use short_label::ShortLabel; | 17 | pub(crate) use short_label::ShortLabel; |
20 | 18 | ||
21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 19 | pub(crate) fn function_declaration(node: &ast::FnDef) -> String { |
22 | FunctionSignature::from(node).to_string() | 20 | let mut buf = String::new(); |
21 | if let Some(vis) = node.visibility() { | ||
22 | format_to!(buf, "{} ", vis); | ||
23 | } | ||
24 | if node.async_token().is_some() { | ||
25 | format_to!(buf, "async "); | ||
26 | } | ||
27 | if node.const_token().is_some() { | ||
28 | format_to!(buf, "const "); | ||
29 | } | ||
30 | if node.unsafe_token().is_some() { | ||
31 | format_to!(buf, "unsafe "); | ||
32 | } | ||
33 | if let Some(abi) = node.abi() { | ||
34 | // Keyword `extern` is included in the string. | ||
35 | format_to!(buf, "{} ", abi); | ||
36 | } | ||
37 | if let Some(name) = node.name() { | ||
38 | format_to!(buf, "fn {}", name) | ||
39 | } | ||
40 | if let Some(type_params) = node.type_param_list() { | ||
41 | format_to!(buf, "{}", type_params); | ||
42 | } | ||
43 | if let Some(param_list) = node.param_list() { | ||
44 | format_to!(buf, "{}", param_list); | ||
45 | } | ||
46 | if let Some(ret_type) = node.ret_type() { | ||
47 | if ret_type.type_ref().is_some() { | ||
48 | format_to!(buf, " {}", ret_type); | ||
49 | } | ||
50 | } | ||
51 | if let Some(where_clause) = node.where_clause() { | ||
52 | format_to!(buf, "\n{}", where_clause); | ||
53 | } | ||
54 | buf | ||
23 | } | 55 | } |
24 | 56 | ||
25 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { | 57 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { |
@@ -44,23 +76,6 @@ pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { | |||
44 | label.trim().to_owned() | 76 | label.trim().to_owned() |
45 | } | 77 | } |
46 | 78 | ||
47 | pub(crate) fn generic_parameters<N: TypeParamsOwner>(node: &N) -> Vec<String> { | ||
48 | let mut res = vec![]; | ||
49 | if let Some(type_params) = node.type_param_list() { | ||
50 | res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); | ||
51 | res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); | ||
52 | } | ||
53 | res | ||
54 | } | ||
55 | |||
56 | pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> { | ||
57 | let mut res = vec![]; | ||
58 | if let Some(clause) = node.where_clause() { | ||
59 | res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); | ||
60 | } | ||
61 | res | ||
62 | } | ||
63 | |||
64 | pub(crate) fn macro_label(node: &ast::MacroCall) -> String { | 79 | pub(crate) fn macro_label(node: &ast::MacroCall) -> String { |
65 | let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); | 80 | let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); |
66 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; | 81 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; |
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs deleted file mode 100644 index 1d39544d3..000000000 --- a/crates/ra_ide/src/display/function_signature.rs +++ /dev/null | |||
@@ -1,321 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | // FIXME: this modules relies on strings and AST way too much, and it should be | ||
4 | // rewritten (matklad 2020-05-07) | ||
5 | use std::{ | ||
6 | convert::From, | ||
7 | fmt::{self, Display}, | ||
8 | }; | ||
9 | |||
10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; | ||
11 | use ra_ide_db::RootDatabase; | ||
12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
13 | use stdx::{split_delim, SepBy}; | ||
14 | |||
15 | use crate::display::{generic_parameters, where_predicates}; | ||
16 | |||
17 | #[derive(Debug)] | ||
18 | pub enum CallableKind { | ||
19 | Function, | ||
20 | StructConstructor, | ||
21 | VariantConstructor, | ||
22 | Macro, | ||
23 | } | ||
24 | |||
25 | /// Contains information about a function signature | ||
26 | #[derive(Debug)] | ||
27 | pub struct FunctionSignature { | ||
28 | pub kind: CallableKind, | ||
29 | /// Optional visibility | ||
30 | pub visibility: Option<String>, | ||
31 | /// Qualifiers like `async`, `unsafe`, ... | ||
32 | pub qualifier: FunctionQualifier, | ||
33 | /// Name of the function | ||
34 | pub name: Option<String>, | ||
35 | /// Documentation for the function | ||
36 | pub doc: Option<Documentation>, | ||
37 | /// Generic parameters | ||
38 | pub generic_parameters: Vec<String>, | ||
39 | /// Parameters of the function | ||
40 | pub parameters: Vec<String>, | ||
41 | /// Parameter names of the function | ||
42 | pub parameter_names: Vec<String>, | ||
43 | /// Parameter types of the function | ||
44 | pub parameter_types: Vec<String>, | ||
45 | /// Optional return type | ||
46 | pub ret_type: Option<String>, | ||
47 | /// Where predicates | ||
48 | pub where_predicates: Vec<String>, | ||
49 | /// Self param presence | ||
50 | pub has_self_param: bool, | ||
51 | } | ||
52 | |||
53 | #[derive(Debug, Default)] | ||
54 | pub struct FunctionQualifier { | ||
55 | // `async` and `const` are mutually exclusive. Do we need to enforcing it here? | ||
56 | pub is_async: bool, | ||
57 | pub is_const: bool, | ||
58 | pub is_unsafe: bool, | ||
59 | /// The string `extern ".."` | ||
60 | pub extern_abi: Option<String>, | ||
61 | } | ||
62 | |||
63 | impl FunctionSignature { | ||
64 | pub(crate) fn from_hir(db: &RootDatabase, function: hir::Function) -> Self { | ||
65 | let ast_node = function.source(db).value; | ||
66 | let mut res = FunctionSignature::from(&ast_node); | ||
67 | res.doc = function.docs(db); | ||
68 | res | ||
69 | } | ||
70 | |||
71 | pub(crate) fn from_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> { | ||
72 | let node: ast::StructDef = st.source(db).value; | ||
73 | if let ast::StructKind::Record(_) = node.kind() { | ||
74 | return None; | ||
75 | }; | ||
76 | |||
77 | let mut params = vec![]; | ||
78 | let mut parameter_types = vec![]; | ||
79 | for field in st.fields(db).into_iter() { | ||
80 | let ty = field.signature_ty(db); | ||
81 | let raw_param = format!("{}", ty.display(db)); | ||
82 | |||
83 | if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) { | ||
84 | parameter_types.push(param_type.to_string()); | ||
85 | } else { | ||
86 | // useful when you have tuple struct | ||
87 | parameter_types.push(raw_param.clone()); | ||
88 | } | ||
89 | params.push(raw_param); | ||
90 | } | ||
91 | |||
92 | Some(FunctionSignature { | ||
93 | kind: CallableKind::StructConstructor, | ||
94 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | ||
95 | // Do we need `const`? | ||
96 | qualifier: Default::default(), | ||
97 | name: node.name().map(|n| n.text().to_string()), | ||
98 | ret_type: node.name().map(|n| n.text().to_string()), | ||
99 | parameters: params, | ||
100 | parameter_names: vec![], | ||
101 | parameter_types, | ||
102 | generic_parameters: generic_parameters(&node), | ||
103 | where_predicates: where_predicates(&node), | ||
104 | doc: st.docs(db), | ||
105 | has_self_param: false, | ||
106 | }) | ||
107 | } | ||
108 | |||
109 | pub(crate) fn from_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> { | ||
110 | let node: ast::EnumVariant = variant.source(db).value; | ||
111 | match node.kind() { | ||
112 | ast::StructKind::Record(_) | ast::StructKind::Unit => return None, | ||
113 | _ => (), | ||
114 | }; | ||
115 | |||
116 | let parent_name = variant.parent_enum(db).name(db).to_string(); | ||
117 | |||
118 | let name = format!("{}::{}", parent_name, variant.name(db)); | ||
119 | |||
120 | let mut params = vec![]; | ||
121 | let mut parameter_types = vec![]; | ||
122 | for field in variant.fields(db).into_iter() { | ||
123 | let ty = field.signature_ty(db); | ||
124 | let raw_param = format!("{}", ty.display(db)); | ||
125 | if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) { | ||
126 | parameter_types.push(param_type.to_string()); | ||
127 | } else { | ||
128 | // The unwrap_or_else is useful when you have tuple | ||
129 | parameter_types.push(raw_param); | ||
130 | } | ||
131 | let name = field.name(db); | ||
132 | |||
133 | params.push(format!("{}: {}", name, ty.display(db))); | ||
134 | } | ||
135 | |||
136 | Some(FunctionSignature { | ||
137 | kind: CallableKind::VariantConstructor, | ||
138 | visibility: None, | ||
139 | // Do we need `const`? | ||
140 | qualifier: Default::default(), | ||
141 | name: Some(name), | ||
142 | ret_type: None, | ||
143 | parameters: params, | ||
144 | parameter_names: vec![], | ||
145 | parameter_types, | ||
146 | generic_parameters: vec![], | ||
147 | where_predicates: vec![], | ||
148 | doc: variant.docs(db), | ||
149 | has_self_param: false, | ||
150 | }) | ||
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 | } | ||
174 | |||
175 | impl From<&'_ ast::FnDef> for FunctionSignature { | ||
176 | fn from(node: &ast::FnDef) -> FunctionSignature { | ||
177 | fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) { | ||
178 | let mut res = vec![]; | ||
179 | let mut res_types = vec![]; | ||
180 | let mut has_self_param = false; | ||
181 | if let Some(param_list) = node.param_list() { | ||
182 | if let Some(self_param) = param_list.self_param() { | ||
183 | has_self_param = true; | ||
184 | let raw_param = self_param.syntax().text().to_string(); | ||
185 | |||
186 | res_types.push( | ||
187 | raw_param | ||
188 | .split(':') | ||
189 | .nth(1) | ||
190 | .and_then(|it| it.get(1..)) | ||
191 | .unwrap_or_else(|| "Self") | ||
192 | .to_string(), | ||
193 | ); | ||
194 | res.push(raw_param); | ||
195 | } | ||
196 | |||
197 | // macro-generated functions are missing whitespace | ||
198 | fn fmt_param(param: ast::Param) -> String { | ||
199 | let text = param.syntax().text().to_string(); | ||
200 | match split_delim(&text, ':') { | ||
201 | Some((left, right)) => format!("{}: {}", left.trim(), right.trim()), | ||
202 | _ => text, | ||
203 | } | ||
204 | } | ||
205 | |||
206 | res.extend(param_list.params().map(fmt_param)); | ||
207 | res_types.extend(param_list.params().map(|param| { | ||
208 | let param_text = param.syntax().text().to_string(); | ||
209 | match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { | ||
210 | Some(it) => it.to_string(), | ||
211 | None => param_text, | ||
212 | } | ||
213 | })); | ||
214 | } | ||
215 | (has_self_param, res, res_types) | ||
216 | } | ||
217 | |||
218 | fn param_name_list(node: &ast::FnDef) -> Vec<String> { | ||
219 | let mut res = vec![]; | ||
220 | if let Some(param_list) = node.param_list() { | ||
221 | if let Some(self_param) = param_list.self_param() { | ||
222 | res.push(self_param.syntax().text().to_string()) | ||
223 | } | ||
224 | |||
225 | res.extend( | ||
226 | param_list | ||
227 | .params() | ||
228 | .map(|param| { | ||
229 | Some( | ||
230 | param | ||
231 | .pat()? | ||
232 | .syntax() | ||
233 | .descendants() | ||
234 | .find_map(ast::Name::cast)? | ||
235 | .text() | ||
236 | .to_string(), | ||
237 | ) | ||
238 | }) | ||
239 | .map(|param| param.unwrap_or_default()), | ||
240 | ); | ||
241 | } | ||
242 | res | ||
243 | } | ||
244 | |||
245 | let (has_self_param, parameters, parameter_types) = param_list(node); | ||
246 | |||
247 | FunctionSignature { | ||
248 | kind: CallableKind::Function, | ||
249 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | ||
250 | qualifier: FunctionQualifier { | ||
251 | is_async: node.async_token().is_some(), | ||
252 | is_const: node.const_token().is_some(), | ||
253 | is_unsafe: node.unsafe_token().is_some(), | ||
254 | extern_abi: node.abi().map(|n| n.to_string()), | ||
255 | }, | ||
256 | name: node.name().map(|n| n.text().to_string()), | ||
257 | ret_type: node | ||
258 | .ret_type() | ||
259 | .and_then(|r| r.type_ref()) | ||
260 | .map(|n| n.syntax().text().to_string()), | ||
261 | parameters, | ||
262 | parameter_names: param_name_list(node), | ||
263 | parameter_types, | ||
264 | generic_parameters: generic_parameters(node), | ||
265 | where_predicates: where_predicates(node), | ||
266 | // docs are processed separately | ||
267 | doc: None, | ||
268 | has_self_param, | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | |||
273 | impl Display for FunctionSignature { | ||
274 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
275 | if let Some(t) = &self.visibility { | ||
276 | write!(f, "{} ", t)?; | ||
277 | } | ||
278 | |||
279 | if self.qualifier.is_async { | ||
280 | write!(f, "async ")?; | ||
281 | } | ||
282 | |||
283 | if self.qualifier.is_const { | ||
284 | write!(f, "const ")?; | ||
285 | } | ||
286 | |||
287 | if self.qualifier.is_unsafe { | ||
288 | write!(f, "unsafe ")?; | ||
289 | } | ||
290 | |||
291 | if let Some(extern_abi) = &self.qualifier.extern_abi { | ||
292 | // Keyword `extern` is included in the string. | ||
293 | write!(f, "{} ", extern_abi)?; | ||
294 | } | ||
295 | |||
296 | if let Some(name) = &self.name { | ||
297 | match self.kind { | ||
298 | CallableKind::Function => write!(f, "fn {}", name)?, | ||
299 | CallableKind::StructConstructor => write!(f, "struct {}", name)?, | ||
300 | CallableKind::VariantConstructor => write!(f, "{}", name)?, | ||
301 | CallableKind::Macro => write!(f, "{}!", name)?, | ||
302 | } | ||
303 | } | ||
304 | |||
305 | if !self.generic_parameters.is_empty() { | ||
306 | write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?; | ||
307 | } | ||
308 | |||
309 | write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?; | ||
310 | |||
311 | if let Some(t) = &self.ret_type { | ||
312 | write!(f, " -> {}", t)?; | ||
313 | } | ||
314 | |||
315 | if !self.where_predicates.is_empty() { | ||
316 | write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n "))?; | ||
317 | } | ||
318 | |||
319 | Ok(()) | ||
320 | } | ||
321 | } | ||
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 8bf2428ed..6dcb9415a 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -22,15 +22,28 @@ use super::short_label::ShortLabel; | |||
22 | /// code, like a function or a struct, but this is not strictly required. | 22 | /// code, like a function or a struct, but this is not strictly required. |
23 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 23 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
24 | pub struct NavigationTarget { | 24 | pub struct NavigationTarget { |
25 | // FIXME: use FileRange? | 25 | pub file_id: FileId, |
26 | file_id: FileId, | 26 | /// Range which encompasses the whole element. |
27 | full_range: TextRange, | 27 | /// |
28 | name: SmolStr, | 28 | /// Should include body, doc comments, attributes, etc. |
29 | kind: SyntaxKind, | 29 | /// |
30 | focus_range: Option<TextRange>, | 30 | /// Clients should use this range to answer "is the cursor inside the |
31 | container_name: Option<SmolStr>, | 31 | /// element?" question. |
32 | description: Option<String>, | 32 | pub full_range: TextRange, |
33 | docs: Option<String>, | 33 | /// A "most interesting" range withing the `full_range`. |
34 | /// | ||
35 | /// Typically, `full_range` is the whole syntax node, including doc | ||
36 | /// comments, and `focus_range` is the range of the identifier. "Most | ||
37 | /// interesting" range within the full range, typically the range of | ||
38 | /// identifier. | ||
39 | /// | ||
40 | /// Clients should place the cursor on this range when navigating to this target. | ||
41 | pub focus_range: Option<TextRange>, | ||
42 | pub name: SmolStr, | ||
43 | pub kind: SyntaxKind, | ||
44 | pub container_name: Option<SmolStr>, | ||
45 | pub description: Option<String>, | ||
46 | pub docs: Option<String>, | ||
34 | } | 47 | } |
35 | 48 | ||
36 | pub(crate) trait ToNav { | 49 | pub(crate) trait ToNav { |
@@ -42,44 +55,9 @@ pub(crate) trait TryToNav { | |||
42 | } | 55 | } |
43 | 56 | ||
44 | impl NavigationTarget { | 57 | impl NavigationTarget { |
45 | /// When `focus_range` is specified, returns it. otherwise | 58 | pub fn focus_or_full_range(&self) -> TextRange { |
46 | /// returns `full_range` | ||
47 | pub fn range(&self) -> TextRange { | ||
48 | self.focus_range.unwrap_or(self.full_range) | 59 | self.focus_range.unwrap_or(self.full_range) |
49 | } | 60 | } |
50 | /// A "most interesting" range withing the `full_range`. | ||
51 | /// | ||
52 | /// Typically, `full_range` is the whole syntax node, | ||
53 | /// including doc comments, and `focus_range` is the range of the identifier. | ||
54 | pub fn focus_range(&self) -> Option<TextRange> { | ||
55 | self.focus_range | ||
56 | } | ||
57 | pub fn full_range(&self) -> TextRange { | ||
58 | self.full_range | ||
59 | } | ||
60 | pub fn file_id(&self) -> FileId { | ||
61 | self.file_id | ||
62 | } | ||
63 | |||
64 | pub fn name(&self) -> &SmolStr { | ||
65 | &self.name | ||
66 | } | ||
67 | |||
68 | pub fn container_name(&self) -> Option<&SmolStr> { | ||
69 | self.container_name.as_ref() | ||
70 | } | ||
71 | |||
72 | pub fn kind(&self) -> SyntaxKind { | ||
73 | self.kind | ||
74 | } | ||
75 | |||
76 | pub fn docs(&self) -> Option<&str> { | ||
77 | self.docs.as_deref() | ||
78 | } | ||
79 | |||
80 | pub fn description(&self) -> Option<&str> { | ||
81 | self.description.as_deref() | ||
82 | } | ||
83 | 61 | ||
84 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 62 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
85 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 63 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
@@ -107,17 +85,12 @@ impl NavigationTarget { | |||
107 | 85 | ||
108 | #[cfg(test)] | 86 | #[cfg(test)] |
109 | pub(crate) fn debug_render(&self) -> String { | 87 | pub(crate) fn debug_render(&self) -> String { |
110 | let mut buf = format!( | 88 | let mut buf = |
111 | "{} {:?} {:?} {:?}", | 89 | format!("{} {:?} {:?} {:?}", self.name, self.kind, self.file_id, self.full_range); |
112 | self.name(), | 90 | if let Some(focus_range) = self.focus_range { |
113 | self.kind(), | ||
114 | self.file_id(), | ||
115 | self.full_range() | ||
116 | ); | ||
117 | if let Some(focus_range) = self.focus_range() { | ||
118 | buf.push_str(&format!(" {:?}", focus_range)) | 91 | buf.push_str(&format!(" {:?}", focus_range)) |
119 | } | 92 | } |
120 | if let Some(container_name) = self.container_name() { | 93 | if let Some(container_name) = &self.container_name { |
121 | buf.push_str(&format!(" {}", container_name)) | 94 | buf.push_str(&format!(" {}", container_name)) |
122 | } | 95 | } |
123 | buf | 96 | buf |
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs index d37260e96..5588130a1 100644 --- a/crates/ra_ide/src/display/short_label.rs +++ b/crates/ra_ide/src/display/short_label.rs | |||
@@ -9,7 +9,7 @@ pub(crate) trait ShortLabel { | |||
9 | 9 | ||
10 | impl ShortLabel for ast::FnDef { | 10 | impl ShortLabel for ast::FnDef { |
11 | fn short_label(&self) -> Option<String> { | 11 | fn short_label(&self) -> Option<String> { |
12 | Some(crate::display::function_label(self)) | 12 | Some(crate::display::function_declaration(self)) |
13 | } | 13 | } |
14 | } | 14 | } |
15 | 15 | ||
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/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index c30b20611..db6d20a37 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -130,7 +130,7 @@ mod tests { | |||
130 | assert_eq!(navs.len(), 1); | 130 | assert_eq!(navs.len(), 1); |
131 | 131 | ||
132 | let nav = navs.pop().unwrap(); | 132 | let nav = navs.pop().unwrap(); |
133 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); | 133 | assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); |
134 | } | 134 | } |
135 | 135 | ||
136 | #[test] | 136 | #[test] |
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs index 9acc960fc..3ee048f28 100644 --- a/crates/ra_ide/src/goto_implementation.rs +++ b/crates/ra_ide/src/goto_implementation.rs | |||
@@ -98,7 +98,7 @@ mod tests { | |||
98 | 98 | ||
99 | let mut actual = navs | 99 | let mut actual = navs |
100 | .into_iter() | 100 | .into_iter() |
101 | .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() }) | 101 | .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) |
102 | .collect::<Vec<_>>(); | 102 | .collect::<Vec<_>>(); |
103 | actual.sort_by_key(key); | 103 | actual.sort_by_key(key); |
104 | 104 | ||
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs index 069cb283e..8f52feea6 100644 --- a/crates/ra_ide/src/goto_type_definition.rs +++ b/crates/ra_ide/src/goto_type_definition.rs | |||
@@ -67,7 +67,7 @@ mod tests { | |||
67 | let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info; | 67 | let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info; |
68 | assert_eq!(navs.len(), 1); | 68 | assert_eq!(navs.len(), 1); |
69 | let nav = navs.pop().unwrap(); | 69 | let nav = navs.pop().unwrap(); |
70 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); | 70 | assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); |
71 | } | 71 | } |
72 | 72 | ||
73 | #[test] | 73 | #[test] |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index a4c97e7f9..d067c339d 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -133,8 +133,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
133 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 133 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
134 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | 134 | fn to_action(nav_target: NavigationTarget) -> HoverAction { |
135 | HoverAction::Implementaion(FilePosition { | 135 | HoverAction::Implementaion(FilePosition { |
136 | file_id: nav_target.file_id(), | 136 | file_id: nav_target.file_id, |
137 | offset: nav_target.range().start(), | 137 | offset: nav_target.focus_or_full_range().start(), |
138 | }) | 138 | }) |
139 | } | 139 | } |
140 | 140 | ||
@@ -1357,11 +1357,11 @@ fn foo_<|>test() {} | |||
1357 | 1, | 1357 | 1, |
1358 | ), | 1358 | ), |
1359 | full_range: 0..24, | 1359 | full_range: 0..24, |
1360 | name: "foo_test", | ||
1361 | kind: FN_DEF, | ||
1362 | focus_range: Some( | 1360 | focus_range: Some( |
1363 | 11..19, | 1361 | 11..19, |
1364 | ), | 1362 | ), |
1363 | name: "foo_test", | ||
1364 | kind: FN_DEF, | ||
1365 | container_name: None, | 1365 | container_name: None, |
1366 | description: None, | 1366 | description: None, |
1367 | docs: None, | 1367 | docs: None, |
@@ -1400,11 +1400,11 @@ mod tests<|> { | |||
1400 | 1, | 1400 | 1, |
1401 | ), | 1401 | ), |
1402 | full_range: 0..46, | 1402 | full_range: 0..46, |
1403 | name: "tests", | ||
1404 | kind: MODULE, | ||
1405 | focus_range: Some( | 1403 | focus_range: Some( |
1406 | 4..9, | 1404 | 4..9, |
1407 | ), | 1405 | ), |
1406 | name: "tests", | ||
1407 | kind: MODULE, | ||
1408 | container_name: None, | 1408 | container_name: None, |
1409 | description: None, | 1409 | description: None, |
1410 | docs: None, | 1410 | docs: None, |
@@ -1439,11 +1439,11 @@ fn main() { let s<|>t = S{ f1:0 }; } | |||
1439 | 1, | 1439 | 1, |
1440 | ), | 1440 | ), |
1441 | full_range: 0..19, | 1441 | full_range: 0..19, |
1442 | name: "S", | ||
1443 | kind: STRUCT_DEF, | ||
1444 | focus_range: Some( | 1442 | focus_range: Some( |
1445 | 7..8, | 1443 | 7..8, |
1446 | ), | 1444 | ), |
1445 | name: "S", | ||
1446 | kind: STRUCT_DEF, | ||
1447 | container_name: None, | 1447 | container_name: None, |
1448 | description: Some( | 1448 | description: Some( |
1449 | "struct S", | 1449 | "struct S", |
@@ -1478,11 +1478,11 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } | |||
1478 | 1, | 1478 | 1, |
1479 | ), | 1479 | ), |
1480 | full_range: 17..37, | 1480 | full_range: 17..37, |
1481 | name: "S", | ||
1482 | kind: STRUCT_DEF, | ||
1483 | focus_range: Some( | 1481 | focus_range: Some( |
1484 | 24..25, | 1482 | 24..25, |
1485 | ), | 1483 | ), |
1484 | name: "S", | ||
1485 | kind: STRUCT_DEF, | ||
1486 | container_name: None, | 1486 | container_name: None, |
1487 | description: Some( | 1487 | description: Some( |
1488 | "struct S", | 1488 | "struct S", |
@@ -1497,11 +1497,11 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } | |||
1497 | 1, | 1497 | 1, |
1498 | ), | 1498 | ), |
1499 | full_range: 0..16, | 1499 | full_range: 0..16, |
1500 | name: "Arg", | ||
1501 | kind: STRUCT_DEF, | ||
1502 | focus_range: Some( | 1500 | focus_range: Some( |
1503 | 7..10, | 1501 | 7..10, |
1504 | ), | 1502 | ), |
1503 | name: "Arg", | ||
1504 | kind: STRUCT_DEF, | ||
1505 | container_name: None, | 1505 | container_name: None, |
1506 | description: Some( | 1506 | description: Some( |
1507 | "struct Arg", | 1507 | "struct Arg", |
@@ -1536,11 +1536,11 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } | |||
1536 | 1, | 1536 | 1, |
1537 | ), | 1537 | ), |
1538 | full_range: 17..37, | 1538 | full_range: 17..37, |
1539 | name: "S", | ||
1540 | kind: STRUCT_DEF, | ||
1541 | focus_range: Some( | 1539 | focus_range: Some( |
1542 | 24..25, | 1540 | 24..25, |
1543 | ), | 1541 | ), |
1542 | name: "S", | ||
1543 | kind: STRUCT_DEF, | ||
1544 | container_name: None, | 1544 | container_name: None, |
1545 | description: Some( | 1545 | description: Some( |
1546 | "struct S", | 1546 | "struct S", |
@@ -1555,11 +1555,11 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } | |||
1555 | 1, | 1555 | 1, |
1556 | ), | 1556 | ), |
1557 | full_range: 0..16, | 1557 | full_range: 0..16, |
1558 | name: "Arg", | ||
1559 | kind: STRUCT_DEF, | ||
1560 | focus_range: Some( | 1558 | focus_range: Some( |
1561 | 7..10, | 1559 | 7..10, |
1562 | ), | 1560 | ), |
1561 | name: "Arg", | ||
1562 | kind: STRUCT_DEF, | ||
1563 | container_name: None, | 1563 | container_name: None, |
1564 | description: Some( | 1564 | description: Some( |
1565 | "struct Arg", | 1565 | "struct Arg", |
@@ -1597,11 +1597,11 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
1597 | 1, | 1597 | 1, |
1598 | ), | 1598 | ), |
1599 | full_range: 0..14, | 1599 | full_range: 0..14, |
1600 | name: "A", | ||
1601 | kind: STRUCT_DEF, | ||
1602 | focus_range: Some( | 1600 | focus_range: Some( |
1603 | 7..8, | 1601 | 7..8, |
1604 | ), | 1602 | ), |
1603 | name: "A", | ||
1604 | kind: STRUCT_DEF, | ||
1605 | container_name: None, | 1605 | container_name: None, |
1606 | description: Some( | 1606 | description: Some( |
1607 | "struct A", | 1607 | "struct A", |
@@ -1616,11 +1616,11 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
1616 | 1, | 1616 | 1, |
1617 | ), | 1617 | ), |
1618 | full_range: 15..29, | 1618 | full_range: 15..29, |
1619 | name: "B", | ||
1620 | kind: STRUCT_DEF, | ||
1621 | focus_range: Some( | 1619 | focus_range: Some( |
1622 | 22..23, | 1620 | 22..23, |
1623 | ), | 1621 | ), |
1622 | name: "B", | ||
1623 | kind: STRUCT_DEF, | ||
1624 | container_name: None, | 1624 | container_name: None, |
1625 | description: Some( | 1625 | description: Some( |
1626 | "struct B", | 1626 | "struct B", |
@@ -1635,11 +1635,11 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
1635 | 1, | 1635 | 1, |
1636 | ), | 1636 | ), |
1637 | full_range: 42..60, | 1637 | full_range: 42..60, |
1638 | name: "C", | ||
1639 | kind: STRUCT_DEF, | ||
1640 | focus_range: Some( | 1638 | focus_range: Some( |
1641 | 53..54, | 1639 | 53..54, |
1642 | ), | 1640 | ), |
1641 | name: "C", | ||
1642 | kind: STRUCT_DEF, | ||
1643 | container_name: None, | 1643 | container_name: None, |
1644 | description: Some( | 1644 | description: Some( |
1645 | "pub struct C", | 1645 | "pub struct C", |
@@ -1674,11 +1674,11 @@ fn main() { let s<|>t = foo(); } | |||
1674 | 1, | 1674 | 1, |
1675 | ), | 1675 | ), |
1676 | full_range: 0..12, | 1676 | full_range: 0..12, |
1677 | name: "Foo", | ||
1678 | kind: TRAIT_DEF, | ||
1679 | focus_range: Some( | 1677 | focus_range: Some( |
1680 | 6..9, | 1678 | 6..9, |
1681 | ), | 1679 | ), |
1680 | name: "Foo", | ||
1681 | kind: TRAIT_DEF, | ||
1682 | container_name: None, | 1682 | container_name: None, |
1683 | description: Some( | 1683 | description: Some( |
1684 | "trait Foo", | 1684 | "trait Foo", |
@@ -1714,11 +1714,11 @@ fn main() { let s<|>t = foo(); } | |||
1714 | 1, | 1714 | 1, |
1715 | ), | 1715 | ), |
1716 | full_range: 0..15, | 1716 | full_range: 0..15, |
1717 | name: "Foo", | ||
1718 | kind: TRAIT_DEF, | ||
1719 | focus_range: Some( | 1717 | focus_range: Some( |
1720 | 6..9, | 1718 | 6..9, |
1721 | ), | 1719 | ), |
1720 | name: "Foo", | ||
1721 | kind: TRAIT_DEF, | ||
1722 | container_name: None, | 1722 | container_name: None, |
1723 | description: Some( | 1723 | description: Some( |
1724 | "trait Foo", | 1724 | "trait Foo", |
@@ -1733,11 +1733,11 @@ fn main() { let s<|>t = foo(); } | |||
1733 | 1, | 1733 | 1, |
1734 | ), | 1734 | ), |
1735 | full_range: 16..25, | 1735 | full_range: 16..25, |
1736 | name: "S", | ||
1737 | kind: STRUCT_DEF, | ||
1738 | focus_range: Some( | 1736 | focus_range: Some( |
1739 | 23..24, | 1737 | 23..24, |
1740 | ), | 1738 | ), |
1739 | name: "S", | ||
1740 | kind: STRUCT_DEF, | ||
1741 | container_name: None, | 1741 | container_name: None, |
1742 | description: Some( | 1742 | description: Some( |
1743 | "struct S", | 1743 | "struct S", |
@@ -1773,11 +1773,11 @@ fn main() { let s<|>t = foo(); } | |||
1773 | 1, | 1773 | 1, |
1774 | ), | 1774 | ), |
1775 | full_range: 0..12, | 1775 | full_range: 0..12, |
1776 | name: "Foo", | ||
1777 | kind: TRAIT_DEF, | ||
1778 | focus_range: Some( | 1776 | focus_range: Some( |
1779 | 6..9, | 1777 | 6..9, |
1780 | ), | 1778 | ), |
1779 | name: "Foo", | ||
1780 | kind: TRAIT_DEF, | ||
1781 | container_name: None, | 1781 | container_name: None, |
1782 | description: Some( | 1782 | description: Some( |
1783 | "trait Foo", | 1783 | "trait Foo", |
@@ -1792,11 +1792,11 @@ fn main() { let s<|>t = foo(); } | |||
1792 | 1, | 1792 | 1, |
1793 | ), | 1793 | ), |
1794 | full_range: 13..25, | 1794 | full_range: 13..25, |
1795 | name: "Bar", | ||
1796 | kind: TRAIT_DEF, | ||
1797 | focus_range: Some( | 1795 | focus_range: Some( |
1798 | 19..22, | 1796 | 19..22, |
1799 | ), | 1797 | ), |
1798 | name: "Bar", | ||
1799 | kind: TRAIT_DEF, | ||
1800 | container_name: None, | 1800 | container_name: None, |
1801 | description: Some( | 1801 | description: Some( |
1802 | "trait Bar", | 1802 | "trait Bar", |
@@ -1835,11 +1835,11 @@ fn main() { let s<|>t = foo(); } | |||
1835 | 1, | 1835 | 1, |
1836 | ), | 1836 | ), |
1837 | full_range: 0..15, | 1837 | full_range: 0..15, |
1838 | name: "Foo", | ||
1839 | kind: TRAIT_DEF, | ||
1840 | focus_range: Some( | 1838 | focus_range: Some( |
1841 | 6..9, | 1839 | 6..9, |
1842 | ), | 1840 | ), |
1841 | name: "Foo", | ||
1842 | kind: TRAIT_DEF, | ||
1843 | container_name: None, | 1843 | container_name: None, |
1844 | description: Some( | 1844 | description: Some( |
1845 | "trait Foo", | 1845 | "trait Foo", |
@@ -1854,11 +1854,11 @@ fn main() { let s<|>t = foo(); } | |||
1854 | 1, | 1854 | 1, |
1855 | ), | 1855 | ), |
1856 | full_range: 16..31, | 1856 | full_range: 16..31, |
1857 | name: "Bar", | ||
1858 | kind: TRAIT_DEF, | ||
1859 | focus_range: Some( | 1857 | focus_range: Some( |
1860 | 22..25, | 1858 | 22..25, |
1861 | ), | 1859 | ), |
1860 | name: "Bar", | ||
1861 | kind: TRAIT_DEF, | ||
1862 | container_name: None, | 1862 | container_name: None, |
1863 | description: Some( | 1863 | description: Some( |
1864 | "trait Bar", | 1864 | "trait Bar", |
@@ -1873,11 +1873,11 @@ fn main() { let s<|>t = foo(); } | |||
1873 | 1, | 1873 | 1, |
1874 | ), | 1874 | ), |
1875 | full_range: 32..44, | 1875 | full_range: 32..44, |
1876 | name: "S1", | ||
1877 | kind: STRUCT_DEF, | ||
1878 | focus_range: Some( | 1876 | focus_range: Some( |
1879 | 39..41, | 1877 | 39..41, |
1880 | ), | 1878 | ), |
1879 | name: "S1", | ||
1880 | kind: STRUCT_DEF, | ||
1881 | container_name: None, | 1881 | container_name: None, |
1882 | description: Some( | 1882 | description: Some( |
1883 | "struct S1", | 1883 | "struct S1", |
@@ -1892,11 +1892,11 @@ fn main() { let s<|>t = foo(); } | |||
1892 | 1, | 1892 | 1, |
1893 | ), | 1893 | ), |
1894 | full_range: 45..57, | 1894 | full_range: 45..57, |
1895 | name: "S2", | ||
1896 | kind: STRUCT_DEF, | ||
1897 | focus_range: Some( | 1895 | focus_range: Some( |
1898 | 52..54, | 1896 | 52..54, |
1899 | ), | 1897 | ), |
1898 | name: "S2", | ||
1899 | kind: STRUCT_DEF, | ||
1900 | container_name: None, | 1900 | container_name: None, |
1901 | description: Some( | 1901 | description: Some( |
1902 | "struct S2", | 1902 | "struct S2", |
@@ -1929,11 +1929,11 @@ fn foo(ar<|>g: &impl Foo) {} | |||
1929 | 1, | 1929 | 1, |
1930 | ), | 1930 | ), |
1931 | full_range: 0..12, | 1931 | full_range: 0..12, |
1932 | name: "Foo", | ||
1933 | kind: TRAIT_DEF, | ||
1934 | focus_range: Some( | 1932 | focus_range: Some( |
1935 | 6..9, | 1933 | 6..9, |
1936 | ), | 1934 | ), |
1935 | name: "Foo", | ||
1936 | kind: TRAIT_DEF, | ||
1937 | container_name: None, | 1937 | container_name: None, |
1938 | description: Some( | 1938 | description: Some( |
1939 | "trait Foo", | 1939 | "trait Foo", |
@@ -1969,11 +1969,11 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
1969 | 1, | 1969 | 1, |
1970 | ), | 1970 | ), |
1971 | full_range: 0..12, | 1971 | full_range: 0..12, |
1972 | name: "Foo", | ||
1973 | kind: TRAIT_DEF, | ||
1974 | focus_range: Some( | 1972 | focus_range: Some( |
1975 | 6..9, | 1973 | 6..9, |
1976 | ), | 1974 | ), |
1975 | name: "Foo", | ||
1976 | kind: TRAIT_DEF, | ||
1977 | container_name: None, | 1977 | container_name: None, |
1978 | description: Some( | 1978 | description: Some( |
1979 | "trait Foo", | 1979 | "trait Foo", |
@@ -1988,11 +1988,11 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
1988 | 1, | 1988 | 1, |
1989 | ), | 1989 | ), |
1990 | full_range: 13..28, | 1990 | full_range: 13..28, |
1991 | name: "Bar", | ||
1992 | kind: TRAIT_DEF, | ||
1993 | focus_range: Some( | 1991 | focus_range: Some( |
1994 | 19..22, | 1992 | 19..22, |
1995 | ), | 1993 | ), |
1994 | name: "Bar", | ||
1995 | kind: TRAIT_DEF, | ||
1996 | container_name: None, | 1996 | container_name: None, |
1997 | description: Some( | 1997 | description: Some( |
1998 | "trait Bar", | 1998 | "trait Bar", |
@@ -2007,11 +2007,11 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
2007 | 1, | 2007 | 1, |
2008 | ), | 2008 | ), |
2009 | full_range: 29..39, | 2009 | full_range: 29..39, |
2010 | name: "S", | ||
2011 | kind: STRUCT_DEF, | ||
2012 | focus_range: Some( | 2010 | focus_range: Some( |
2013 | 36..37, | 2011 | 36..37, |
2014 | ), | 2012 | ), |
2013 | name: "S", | ||
2014 | kind: STRUCT_DEF, | ||
2015 | container_name: None, | 2015 | container_name: None, |
2016 | description: Some( | 2016 | description: Some( |
2017 | "struct S", | 2017 | "struct S", |
@@ -2045,11 +2045,11 @@ fn foo(ar<|>g: &impl Foo<S>) {} | |||
2045 | 1, | 2045 | 1, |
2046 | ), | 2046 | ), |
2047 | full_range: 0..15, | 2047 | full_range: 0..15, |
2048 | name: "Foo", | ||
2049 | kind: TRAIT_DEF, | ||
2050 | focus_range: Some( | 2048 | focus_range: Some( |
2051 | 6..9, | 2049 | 6..9, |
2052 | ), | 2050 | ), |
2051 | name: "Foo", | ||
2052 | kind: TRAIT_DEF, | ||
2053 | container_name: None, | 2053 | container_name: None, |
2054 | description: Some( | 2054 | description: Some( |
2055 | "trait Foo", | 2055 | "trait Foo", |
@@ -2064,11 +2064,11 @@ fn foo(ar<|>g: &impl Foo<S>) {} | |||
2064 | 1, | 2064 | 1, |
2065 | ), | 2065 | ), |
2066 | full_range: 16..27, | 2066 | full_range: 16..27, |
2067 | name: "S", | ||
2068 | kind: STRUCT_DEF, | ||
2069 | focus_range: Some( | 2067 | focus_range: Some( |
2070 | 23..24, | 2068 | 23..24, |
2071 | ), | 2069 | ), |
2070 | name: "S", | ||
2071 | kind: STRUCT_DEF, | ||
2072 | container_name: None, | 2072 | container_name: None, |
2073 | description: Some( | 2073 | description: Some( |
2074 | "struct S", | 2074 | "struct S", |
@@ -2107,11 +2107,11 @@ fn main() { let s<|>t = foo(); } | |||
2107 | 1, | 2107 | 1, |
2108 | ), | 2108 | ), |
2109 | full_range: 42..55, | 2109 | full_range: 42..55, |
2110 | name: "B", | ||
2111 | kind: STRUCT_DEF, | ||
2112 | focus_range: Some( | 2110 | focus_range: Some( |
2113 | 49..50, | 2111 | 49..50, |
2114 | ), | 2112 | ), |
2113 | name: "B", | ||
2114 | kind: STRUCT_DEF, | ||
2115 | container_name: None, | 2115 | container_name: None, |
2116 | description: Some( | 2116 | description: Some( |
2117 | "struct B", | 2117 | "struct B", |
@@ -2126,11 +2126,11 @@ fn main() { let s<|>t = foo(); } | |||
2126 | 1, | 2126 | 1, |
2127 | ), | 2127 | ), |
2128 | full_range: 0..12, | 2128 | full_range: 0..12, |
2129 | name: "Foo", | ||
2130 | kind: TRAIT_DEF, | ||
2131 | focus_range: Some( | 2129 | focus_range: Some( |
2132 | 6..9, | 2130 | 6..9, |
2133 | ), | 2131 | ), |
2132 | name: "Foo", | ||
2133 | kind: TRAIT_DEF, | ||
2134 | container_name: None, | 2134 | container_name: None, |
2135 | description: Some( | 2135 | description: Some( |
2136 | "trait Foo", | 2136 | "trait Foo", |
@@ -2163,11 +2163,11 @@ fn foo(ar<|>g: &dyn Foo) {} | |||
2163 | 1, | 2163 | 1, |
2164 | ), | 2164 | ), |
2165 | full_range: 0..12, | 2165 | full_range: 0..12, |
2166 | name: "Foo", | ||
2167 | kind: TRAIT_DEF, | ||
2168 | focus_range: Some( | 2166 | focus_range: Some( |
2169 | 6..9, | 2167 | 6..9, |
2170 | ), | 2168 | ), |
2169 | name: "Foo", | ||
2170 | kind: TRAIT_DEF, | ||
2171 | container_name: None, | 2171 | container_name: None, |
2172 | description: Some( | 2172 | description: Some( |
2173 | "trait Foo", | 2173 | "trait Foo", |
@@ -2201,11 +2201,11 @@ fn foo(ar<|>g: &dyn Foo<S>) {} | |||
2201 | 1, | 2201 | 1, |
2202 | ), | 2202 | ), |
2203 | full_range: 0..15, | 2203 | full_range: 0..15, |
2204 | name: "Foo", | ||
2205 | kind: TRAIT_DEF, | ||
2206 | focus_range: Some( | 2204 | focus_range: Some( |
2207 | 6..9, | 2205 | 6..9, |
2208 | ), | 2206 | ), |
2207 | name: "Foo", | ||
2208 | kind: TRAIT_DEF, | ||
2209 | container_name: None, | 2209 | container_name: None, |
2210 | description: Some( | 2210 | description: Some( |
2211 | "trait Foo", | 2211 | "trait Foo", |
@@ -2220,11 +2220,11 @@ fn foo(ar<|>g: &dyn Foo<S>) {} | |||
2220 | 1, | 2220 | 1, |
2221 | ), | 2221 | ), |
2222 | full_range: 16..27, | 2222 | full_range: 16..27, |
2223 | name: "S", | ||
2224 | kind: STRUCT_DEF, | ||
2225 | focus_range: Some( | 2223 | focus_range: Some( |
2226 | 23..24, | 2224 | 23..24, |
2227 | ), | 2225 | ), |
2226 | name: "S", | ||
2227 | kind: STRUCT_DEF, | ||
2228 | container_name: None, | 2228 | container_name: None, |
2229 | description: Some( | 2229 | description: Some( |
2230 | "struct S", | 2230 | "struct S", |
@@ -2261,11 +2261,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2261 | 1, | 2261 | 1, |
2262 | ), | 2262 | ), |
2263 | full_range: 0..21, | 2263 | full_range: 0..21, |
2264 | name: "ImplTrait", | ||
2265 | kind: TRAIT_DEF, | ||
2266 | focus_range: Some( | 2264 | focus_range: Some( |
2267 | 6..15, | 2265 | 6..15, |
2268 | ), | 2266 | ), |
2267 | name: "ImplTrait", | ||
2268 | kind: TRAIT_DEF, | ||
2269 | container_name: None, | 2269 | container_name: None, |
2270 | description: Some( | 2270 | description: Some( |
2271 | "trait ImplTrait", | 2271 | "trait ImplTrait", |
@@ -2280,11 +2280,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2280 | 1, | 2280 | 1, |
2281 | ), | 2281 | ), |
2282 | full_range: 43..57, | 2282 | full_range: 43..57, |
2283 | name: "B", | ||
2284 | kind: STRUCT_DEF, | ||
2285 | focus_range: Some( | 2283 | focus_range: Some( |
2286 | 50..51, | 2284 | 50..51, |
2287 | ), | 2285 | ), |
2286 | name: "B", | ||
2287 | kind: STRUCT_DEF, | ||
2288 | container_name: None, | 2288 | container_name: None, |
2289 | description: Some( | 2289 | description: Some( |
2290 | "struct B", | 2290 | "struct B", |
@@ -2299,11 +2299,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2299 | 1, | 2299 | 1, |
2300 | ), | 2300 | ), |
2301 | full_range: 22..42, | 2301 | full_range: 22..42, |
2302 | name: "DynTrait", | ||
2303 | kind: TRAIT_DEF, | ||
2304 | focus_range: Some( | 2302 | focus_range: Some( |
2305 | 28..36, | 2303 | 28..36, |
2306 | ), | 2304 | ), |
2305 | name: "DynTrait", | ||
2306 | kind: TRAIT_DEF, | ||
2307 | container_name: None, | 2307 | container_name: None, |
2308 | description: Some( | 2308 | description: Some( |
2309 | "trait DynTrait", | 2309 | "trait DynTrait", |
@@ -2318,11 +2318,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2318 | 1, | 2318 | 1, |
2319 | ), | 2319 | ), |
2320 | full_range: 58..69, | 2320 | full_range: 58..69, |
2321 | name: "S", | ||
2322 | kind: STRUCT_DEF, | ||
2323 | focus_range: Some( | 2321 | focus_range: Some( |
2324 | 65..66, | 2322 | 65..66, |
2325 | ), | 2323 | ), |
2324 | name: "S", | ||
2325 | kind: STRUCT_DEF, | ||
2326 | container_name: None, | 2326 | container_name: None, |
2327 | description: Some( | 2327 | description: Some( |
2328 | "struct S", | 2328 | "struct S", |
@@ -2366,11 +2366,11 @@ fn main() { let s<|>t = test().get(); } | |||
2366 | 1, | 2366 | 1, |
2367 | ), | 2367 | ), |
2368 | full_range: 0..62, | 2368 | full_range: 0..62, |
2369 | name: "Foo", | ||
2370 | kind: TRAIT_DEF, | ||
2371 | focus_range: Some( | 2369 | focus_range: Some( |
2372 | 6..9, | 2370 | 6..9, |
2373 | ), | 2371 | ), |
2372 | name: "Foo", | ||
2373 | kind: TRAIT_DEF, | ||
2374 | container_name: None, | 2374 | container_name: None, |
2375 | description: Some( | 2375 | description: Some( |
2376 | "trait Foo", | 2376 | "trait Foo", |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 3cbae8a45..43a5e29b5 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -1,14 +1,16 @@ | |||
1 | use hir::{Adt, HirDisplay, Semantics, Type}; | 1 | use hir::{Adt, Callable, HirDisplay, Semantics, Type}; |
2 | use ra_ide_db::RootDatabase; | 2 | use ra_ide_db::RootDatabase; |
3 | use ra_prof::profile; | 3 | use ra_prof::profile; |
4 | use ra_syntax::{ | 4 | 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::FileId; | ||
11 | use ast::NameOwner; | ||
12 | use either::Either; | ||
13 | |||
12 | #[derive(Clone, Debug, PartialEq, Eq)] | 14 | #[derive(Clone, Debug, PartialEq, Eq)] |
13 | pub struct InlayHintsConfig { | 15 | pub struct InlayHintsConfig { |
14 | pub type_hints: bool, | 16 | pub type_hints: bool, |
@@ -150,23 +152,26 @@ fn get_param_name_hints( | |||
150 | _ => return None, | 152 | _ => return None, |
151 | }; | 153 | }; |
152 | 154 | ||
153 | let fn_signature = get_fn_signature(sema, &expr)?; | 155 | let callable = get_callable(sema, &expr)?; |
154 | let n_params_to_skip = | 156 | let hints = callable |
155 | if fn_signature.has_self_param && matches!(&expr, ast::Expr::MethodCallExpr(_)) { | 157 | .params(sema.db) |
156 | 1 | 158 | .into_iter() |
157 | } else { | ||
158 | 0 | ||
159 | }; | ||
160 | let hints = fn_signature | ||
161 | .parameter_names | ||
162 | .iter() | ||
163 | .skip(n_params_to_skip) | ||
164 | .zip(args) | 159 | .zip(args) |
165 | .filter(|(param, arg)| should_show_param_name_hint(sema, &fn_signature, param, &arg)) | 160 | .filter_map(|((param, _ty), arg)| match param? { |
161 | Either::Left(self_param) => Some((self_param.to_string(), arg)), | ||
162 | Either::Right(pat) => { | ||
163 | let param_name = match pat { | ||
164 | ast::Pat::BindPat(it) => it.name()?.to_string(), | ||
165 | it => it.to_string(), | ||
166 | }; | ||
167 | Some((param_name, arg)) | ||
168 | } | ||
169 | }) | ||
170 | .filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, ¶m_name, &arg)) | ||
166 | .map(|(param_name, arg)| InlayHint { | 171 | .map(|(param_name, arg)| InlayHint { |
167 | range: arg.syntax().text_range(), | 172 | range: arg.syntax().text_range(), |
168 | kind: InlayKind::ParameterHint, | 173 | kind: InlayKind::ParameterHint, |
169 | label: param_name.into(), | 174 | label: param_name.to_string().into(), |
170 | }); | 175 | }); |
171 | 176 | ||
172 | acc.extend(hints); | 177 | acc.extend(hints); |
@@ -250,28 +255,28 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ | |||
250 | 255 | ||
251 | fn should_show_param_name_hint( | 256 | fn should_show_param_name_hint( |
252 | sema: &Semantics<RootDatabase>, | 257 | sema: &Semantics<RootDatabase>, |
253 | fn_signature: &FunctionSignature, | 258 | callable: &Callable, |
254 | param_name: &str, | 259 | param_name: &str, |
255 | argument: &ast::Expr, | 260 | argument: &ast::Expr, |
256 | ) -> bool { | 261 | ) -> bool { |
257 | let param_name = param_name.trim_start_matches('_'); | 262 | let param_name = param_name.trim_start_matches('_'); |
263 | let fn_name = match callable.kind() { | ||
264 | hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()), | ||
265 | hir::CallableKind::TupleStruct(_) | ||
266 | | hir::CallableKind::TupleEnumVariant(_) | ||
267 | | hir::CallableKind::Closure => None, | ||
268 | }; | ||
258 | if param_name.is_empty() | 269 | if param_name.is_empty() |
259 | || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) | 270 | || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_')) |
260 | || is_argument_similar_to_param_name(sema, argument, param_name) | 271 | || is_argument_similar_to_param_name(sema, argument, param_name) |
261 | || param_name.starts_with("ra_fixture") | 272 | || param_name.starts_with("ra_fixture") |
262 | { | 273 | { |
263 | return false; | 274 | return false; |
264 | } | 275 | } |
265 | 276 | ||
266 | let parameters_len = if fn_signature.has_self_param { | ||
267 | fn_signature.parameters.len() - 1 | ||
268 | } else { | ||
269 | fn_signature.parameters.len() | ||
270 | }; | ||
271 | |||
272 | // avoid displaying hints for common functions like map, filter, etc. | 277 | // avoid displaying hints for common functions like map, filter, etc. |
273 | // or other obvious words used in std | 278 | // or other obvious words used in std |
274 | !(parameters_len == 1 && is_obvious_param(param_name)) | 279 | !(callable.n_params() == 1 && is_obvious_param(param_name)) |
275 | } | 280 | } |
276 | 281 | ||
277 | fn is_argument_similar_to_param_name( | 282 | fn is_argument_similar_to_param_name( |
@@ -318,27 +323,10 @@ fn is_obvious_param(param_name: &str) -> bool { | |||
318 | param_name.len() == 1 || is_obvious_param_name | 323 | param_name.len() == 1 || is_obvious_param_name |
319 | } | 324 | } |
320 | 325 | ||
321 | fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { | 326 | fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Callable> { |
322 | match expr { | 327 | match expr { |
323 | ast::Expr::CallExpr(expr) => { | 328 | ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db), |
324 | // FIXME: Type::as_callable is broken for closures | 329 | ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr), |
325 | let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; | ||
326 | match callable_def { | ||
327 | hir::CallableDefId::FunctionId(it) => { | ||
328 | Some(FunctionSignature::from_hir(sema.db, it.into())) | ||
329 | } | ||
330 | hir::CallableDefId::StructId(it) => { | ||
331 | FunctionSignature::from_struct(sema.db, it.into()) | ||
332 | } | ||
333 | hir::CallableDefId::EnumVariantId(it) => { | ||
334 | FunctionSignature::from_enum_variant(sema.db, it.into()) | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | ast::Expr::MethodCallExpr(expr) => { | ||
339 | let fn_def = sema.resolve_method_call(&expr)?; | ||
340 | Some(FunctionSignature::from_hir(sema.db, fn_def)) | ||
341 | } | ||
342 | _ => None, | 330 | _ => None, |
343 | } | 331 | } |
344 | } | 332 | } |
@@ -360,7 +348,7 @@ mod tests { | |||
360 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 348 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
361 | let actual = | 349 | let actual = |
362 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); | 350 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); |
363 | assert_eq!(expected, actual); | 351 | assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual); |
364 | } | 352 | } |
365 | 353 | ||
366 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { | 354 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 5d1f64e19..353f430ff 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. |
@@ -542,8 +545,8 @@ mod tests { | |||
542 | 545 | ||
543 | let s = symbols.pop().unwrap(); | 546 | let s = symbols.pop().unwrap(); |
544 | 547 | ||
545 | assert_eq!(s.name(), "FooInner"); | 548 | assert_eq!(s.name, "FooInner"); |
546 | assert!(s.container_name().is_none()); | 549 | assert!(s.container_name.is_none()); |
547 | } | 550 | } |
548 | 551 | ||
549 | #[test] | 552 | #[test] |
@@ -558,8 +561,8 @@ fn foo() { | |||
558 | 561 | ||
559 | let s = symbols.pop().unwrap(); | 562 | let s = symbols.pop().unwrap(); |
560 | 563 | ||
561 | assert_eq!(s.name(), "FooInner"); | 564 | assert_eq!(s.name, "FooInner"); |
562 | assert_eq!(s.container_name(), Some(&SmolStr::new("foo"))); | 565 | assert_eq!(s.container_name, Some(SmolStr::new("foo"))); |
563 | 566 | ||
564 | let code = r#" | 567 | let code = r#" |
565 | mod foo { | 568 | mod foo { |
@@ -571,8 +574,8 @@ mod foo { | |||
571 | 574 | ||
572 | let s = symbols.pop().unwrap(); | 575 | let s = symbols.pop().unwrap(); |
573 | 576 | ||
574 | assert_eq!(s.name(), "FooInner"); | 577 | assert_eq!(s.name, "FooInner"); |
575 | assert_eq!(s.container_name(), Some(&SmolStr::new("foo"))); | 578 | assert_eq!(s.container_name, Some(SmolStr::new("foo"))); |
576 | } | 579 | } |
577 | 580 | ||
578 | #[test] | 581 | #[test] |
@@ -585,8 +588,8 @@ struct Foo; | |||
585 | 588 | ||
586 | let symbols = get_symbols_matching(code, "Foo"); | 589 | let symbols = get_symbols_matching(code, "Foo"); |
587 | 590 | ||
588 | let fn_match = symbols.iter().find(|s| s.name() == "foo").map(|s| s.kind()); | 591 | let fn_match = symbols.iter().find(|s| s.name == "foo").map(|s| s.kind); |
589 | let struct_match = symbols.iter().find(|s| s.name() == "Foo").map(|s| s.kind()); | 592 | let struct_match = symbols.iter().find(|s| s.name == "Foo").map(|s| s.kind); |
590 | 593 | ||
591 | assert_eq!(fn_match, Some(FN_DEF)); | 594 | assert_eq!(fn_match, Some(FN_DEF)); |
592 | assert_eq!(struct_match, Some(STRUCT_DEF)); | 595 | assert_eq!(struct_match, Some(STRUCT_DEF)); |
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index c2b0d5efe..fe1c074d1 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -74,8 +74,8 @@ impl IntoIterator for ReferenceSearchResult { | |||
74 | let mut v = Vec::with_capacity(self.len()); | 74 | let mut v = Vec::with_capacity(self.len()); |
75 | v.push(Reference { | 75 | v.push(Reference { |
76 | file_range: FileRange { | 76 | file_range: FileRange { |
77 | file_id: self.declaration.nav.file_id(), | 77 | file_id: self.declaration.nav.file_id, |
78 | range: self.declaration.nav.range(), | 78 | range: self.declaration.nav.focus_or_full_range(), |
79 | }, | 79 | }, |
80 | kind: self.declaration.kind, | 80 | kind: self.declaration.kind, |
81 | access: self.declaration.access, | 81 | access: self.declaration.access, |
@@ -112,7 +112,7 @@ pub(crate) fn find_all_refs( | |||
112 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) | 112 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) |
113 | .collect(); | 113 | .collect(); |
114 | 114 | ||
115 | let decl_range = def.try_to_nav(sema.db)?.range(); | 115 | let decl_range = def.try_to_nav(sema.db)?.focus_or_full_range(); |
116 | 116 | ||
117 | let declaration = Declaration { | 117 | let declaration = Declaration { |
118 | nav: def.try_to_nav(sema.db)?, | 118 | nav: def.try_to_nav(sema.db)?, |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index ed15d6494..0994beec5 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -299,11 +299,11 @@ fn bench() {} | |||
299 | 1, | 299 | 1, |
300 | ), | 300 | ), |
301 | full_range: 1..13, | 301 | full_range: 1..13, |
302 | name: "main", | ||
303 | kind: FN_DEF, | ||
304 | focus_range: Some( | 302 | focus_range: Some( |
305 | 4..8, | 303 | 4..8, |
306 | ), | 304 | ), |
305 | name: "main", | ||
306 | kind: FN_DEF, | ||
307 | container_name: None, | 307 | container_name: None, |
308 | description: None, | 308 | description: None, |
309 | docs: None, | 309 | docs: None, |
@@ -317,11 +317,11 @@ fn bench() {} | |||
317 | 1, | 317 | 1, |
318 | ), | 318 | ), |
319 | full_range: 15..39, | 319 | full_range: 15..39, |
320 | name: "test_foo", | ||
321 | kind: FN_DEF, | ||
322 | focus_range: Some( | 320 | focus_range: Some( |
323 | 26..34, | 321 | 26..34, |
324 | ), | 322 | ), |
323 | name: "test_foo", | ||
324 | kind: FN_DEF, | ||
325 | container_name: None, | 325 | container_name: None, |
326 | description: None, | 326 | description: None, |
327 | docs: None, | 327 | docs: None, |
@@ -342,11 +342,11 @@ fn bench() {} | |||
342 | 1, | 342 | 1, |
343 | ), | 343 | ), |
344 | full_range: 41..75, | 344 | full_range: 41..75, |
345 | name: "test_foo", | ||
346 | kind: FN_DEF, | ||
347 | focus_range: Some( | 345 | focus_range: Some( |
348 | 62..70, | 346 | 62..70, |
349 | ), | 347 | ), |
348 | name: "test_foo", | ||
349 | kind: FN_DEF, | ||
350 | container_name: None, | 350 | container_name: None, |
351 | description: None, | 351 | description: None, |
352 | docs: None, | 352 | docs: None, |
@@ -367,11 +367,11 @@ fn bench() {} | |||
367 | 1, | 367 | 1, |
368 | ), | 368 | ), |
369 | full_range: 77..99, | 369 | full_range: 77..99, |
370 | name: "bench", | ||
371 | kind: FN_DEF, | ||
372 | focus_range: Some( | 370 | focus_range: Some( |
373 | 89..94, | 371 | 89..94, |
374 | ), | 372 | ), |
373 | name: "bench", | ||
374 | kind: FN_DEF, | ||
375 | container_name: None, | 375 | container_name: None, |
376 | description: None, | 376 | description: None, |
377 | docs: None, | 377 | docs: None, |
@@ -410,11 +410,11 @@ fn foo() {} | |||
410 | 1, | 410 | 1, |
411 | ), | 411 | ), |
412 | full_range: 1..13, | 412 | full_range: 1..13, |
413 | name: "main", | ||
414 | kind: FN_DEF, | ||
415 | focus_range: Some( | 413 | focus_range: Some( |
416 | 4..8, | 414 | 4..8, |
417 | ), | 415 | ), |
416 | name: "main", | ||
417 | kind: FN_DEF, | ||
418 | container_name: None, | 418 | container_name: None, |
419 | description: None, | 419 | description: None, |
420 | docs: None, | 420 | docs: None, |
@@ -428,9 +428,9 @@ fn foo() {} | |||
428 | 1, | 428 | 1, |
429 | ), | 429 | ), |
430 | full_range: 15..57, | 430 | full_range: 15..57, |
431 | focus_range: None, | ||
431 | name: "foo", | 432 | name: "foo", |
432 | kind: FN_DEF, | 433 | kind: FN_DEF, |
433 | focus_range: None, | ||
434 | container_name: None, | 434 | container_name: None, |
435 | description: None, | 435 | description: None, |
436 | docs: None, | 436 | docs: None, |
@@ -472,11 +472,11 @@ impl Data { | |||
472 | 1, | 472 | 1, |
473 | ), | 473 | ), |
474 | full_range: 1..13, | 474 | full_range: 1..13, |
475 | name: "main", | ||
476 | kind: FN_DEF, | ||
477 | focus_range: Some( | 475 | focus_range: Some( |
478 | 4..8, | 476 | 4..8, |
479 | ), | 477 | ), |
478 | name: "main", | ||
479 | kind: FN_DEF, | ||
480 | container_name: None, | 480 | container_name: None, |
481 | description: None, | 481 | description: None, |
482 | docs: None, | 482 | docs: None, |
@@ -490,9 +490,9 @@ impl Data { | |||
490 | 1, | 490 | 1, |
491 | ), | 491 | ), |
492 | full_range: 44..98, | 492 | full_range: 44..98, |
493 | focus_range: None, | ||
493 | name: "foo", | 494 | name: "foo", |
494 | kind: FN_DEF, | 495 | kind: FN_DEF, |
495 | focus_range: None, | ||
496 | container_name: None, | 496 | container_name: None, |
497 | description: None, | 497 | description: None, |
498 | docs: None, | 498 | docs: None, |
@@ -529,11 +529,11 @@ mod test_mod { | |||
529 | 1, | 529 | 1, |
530 | ), | 530 | ), |
531 | full_range: 1..51, | 531 | full_range: 1..51, |
532 | name: "test_mod", | ||
533 | kind: MODULE, | ||
534 | focus_range: Some( | 532 | focus_range: Some( |
535 | 5..13, | 533 | 5..13, |
536 | ), | 534 | ), |
535 | name: "test_mod", | ||
536 | kind: MODULE, | ||
537 | container_name: None, | 537 | container_name: None, |
538 | description: None, | 538 | description: None, |
539 | docs: None, | 539 | docs: None, |
@@ -549,11 +549,11 @@ mod test_mod { | |||
549 | 1, | 549 | 1, |
550 | ), | 550 | ), |
551 | full_range: 20..49, | 551 | full_range: 20..49, |
552 | name: "test_foo1", | ||
553 | kind: FN_DEF, | ||
554 | focus_range: Some( | 552 | focus_range: Some( |
555 | 35..44, | 553 | 35..44, |
556 | ), | 554 | ), |
555 | name: "test_foo1", | ||
556 | kind: FN_DEF, | ||
557 | container_name: None, | 557 | container_name: None, |
558 | description: None, | 558 | description: None, |
559 | docs: None, | 559 | docs: None, |
@@ -595,11 +595,11 @@ mod foo { | |||
595 | 1, | 595 | 1, |
596 | ), | 596 | ), |
597 | full_range: 15..77, | 597 | full_range: 15..77, |
598 | name: "test_mod", | ||
599 | kind: MODULE, | ||
600 | focus_range: Some( | 598 | focus_range: Some( |
601 | 19..27, | 599 | 19..27, |
602 | ), | 600 | ), |
601 | name: "test_mod", | ||
602 | kind: MODULE, | ||
603 | container_name: None, | 603 | container_name: None, |
604 | description: None, | 604 | description: None, |
605 | docs: None, | 605 | docs: None, |
@@ -615,11 +615,11 @@ mod foo { | |||
615 | 1, | 615 | 1, |
616 | ), | 616 | ), |
617 | full_range: 38..71, | 617 | full_range: 38..71, |
618 | name: "test_foo1", | ||
619 | kind: FN_DEF, | ||
620 | focus_range: Some( | 618 | focus_range: Some( |
621 | 57..66, | 619 | 57..66, |
622 | ), | 620 | ), |
621 | name: "test_foo1", | ||
622 | kind: FN_DEF, | ||
623 | container_name: None, | 623 | container_name: None, |
624 | description: None, | 624 | description: None, |
625 | docs: None, | 625 | docs: None, |
@@ -663,11 +663,11 @@ mod foo { | |||
663 | 1, | 663 | 1, |
664 | ), | 664 | ), |
665 | full_range: 33..107, | 665 | full_range: 33..107, |
666 | name: "test_mod", | ||
667 | kind: MODULE, | ||
668 | focus_range: Some( | 666 | focus_range: Some( |
669 | 37..45, | 667 | 37..45, |
670 | ), | 668 | ), |
669 | name: "test_mod", | ||
670 | kind: MODULE, | ||
671 | container_name: None, | 671 | container_name: None, |
672 | description: None, | 672 | description: None, |
673 | docs: None, | 673 | docs: None, |
@@ -683,11 +683,11 @@ mod foo { | |||
683 | 1, | 683 | 1, |
684 | ), | 684 | ), |
685 | full_range: 60..97, | 685 | full_range: 60..97, |
686 | name: "test_foo1", | ||
687 | kind: FN_DEF, | ||
688 | focus_range: Some( | 686 | focus_range: Some( |
689 | 83..92, | 687 | 83..92, |
690 | ), | 688 | ), |
689 | name: "test_foo1", | ||
690 | kind: FN_DEF, | ||
691 | container_name: None, | 691 | container_name: None, |
692 | description: None, | 692 | description: None, |
693 | docs: None, | 693 | docs: None, |
@@ -726,11 +726,11 @@ fn test_foo1() {} | |||
726 | 1, | 726 | 1, |
727 | ), | 727 | ), |
728 | full_range: 1..50, | 728 | full_range: 1..50, |
729 | name: "test_foo1", | ||
730 | kind: FN_DEF, | ||
731 | focus_range: Some( | 729 | focus_range: Some( |
732 | 36..45, | 730 | 36..45, |
733 | ), | 731 | ), |
732 | name: "test_foo1", | ||
733 | kind: FN_DEF, | ||
734 | container_name: None, | 734 | container_name: None, |
735 | description: None, | 735 | description: None, |
736 | docs: None, | 736 | docs: None, |
@@ -774,11 +774,11 @@ fn test_foo1() {} | |||
774 | 1, | 774 | 1, |
775 | ), | 775 | ), |
776 | full_range: 1..72, | 776 | full_range: 1..72, |
777 | name: "test_foo1", | ||
778 | kind: FN_DEF, | ||
779 | focus_range: Some( | 777 | focus_range: Some( |
780 | 58..67, | 778 | 58..67, |
781 | ), | 779 | ), |
780 | name: "test_foo1", | ||
781 | kind: FN_DEF, | ||
782 | container_name: None, | 782 | container_name: None, |
783 | description: None, | 783 | description: None, |
784 | docs: None, | 784 | docs: None, |
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 83776d2b6..d3ce744b4 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -39,7 +39,6 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>"; | |||
39 | // Some features trigger on typing certain characters: | 39 | // Some features trigger on typing certain characters: |
40 | // | 40 | // |
41 | // - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression | 41 | // - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression |
42 | // - Enter inside comments automatically inserts `///` | ||
43 | // - typing `.` in a chain method call auto-indents | 42 | // - typing `.` in a chain method call auto-indents |
44 | pub(crate) fn on_char_typed( | 43 | pub(crate) fn on_char_typed( |
45 | db: &RootDatabase, | 44 | db: &RootDatabase, |
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs index 2faaa8ff0..143b1ae41 100644 --- a/crates/ra_ide/src/typing/on_enter.rs +++ b/crates/ra_ide/src/typing/on_enter.rs | |||
@@ -7,10 +7,31 @@ use ra_syntax::{ | |||
7 | ast::{self, AstToken}, | 7 | ast::{self, AstToken}, |
8 | AstNode, SmolStr, SourceFile, | 8 | AstNode, SmolStr, SourceFile, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxToken, TextSize, TokenAtOffset, | 10 | SyntaxToken, TextRange, TextSize, TokenAtOffset, |
11 | }; | 11 | }; |
12 | use ra_text_edit::TextEdit; | 12 | use ra_text_edit::TextEdit; |
13 | use test_utils::mark; | ||
13 | 14 | ||
15 | // Feature: On Enter | ||
16 | // | ||
17 | // rust-analyzer can override kbd:[Enter] key to make it smarter: | ||
18 | // | ||
19 | // - kbd:[Enter] inside triple-slash comments automatically inserts `///` | ||
20 | // - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//` | ||
21 | // | ||
22 | // This action needs to be assigned to shortcut explicitly. | ||
23 | // | ||
24 | // VS Code:: | ||
25 | // | ||
26 | // Add the following to `keybindings.json`: | ||
27 | // [source,json] | ||
28 | // ---- | ||
29 | // { | ||
30 | // "key": "Enter", | ||
31 | // "command": "rust-analyzer.onEnter", | ||
32 | // "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" | ||
33 | // } | ||
34 | // ---- | ||
14 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { | 35 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { |
15 | let parse = db.parse(position.file_id); | 36 | let parse = db.parse(position.file_id); |
16 | let file = parse.tree(); | 37 | let file = parse.tree(); |
@@ -30,15 +51,25 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text | |||
30 | return None; | 51 | return None; |
31 | } | 52 | } |
32 | 53 | ||
54 | let mut remove_last_space = false; | ||
33 | // Continuing single-line non-doc comments (like this one :) ) is annoying | 55 | // Continuing single-line non-doc comments (like this one :) ) is annoying |
34 | if prefix == "//" && comment_range.end() == position.offset && !followed_by_comment(&comment) { | 56 | if prefix == "//" && comment_range.end() == position.offset { |
35 | return None; | 57 | if comment.text().ends_with(' ') { |
58 | mark::hit!(continues_end_of_line_comment_with_space); | ||
59 | remove_last_space = true; | ||
60 | } else if !followed_by_comment(&comment) { | ||
61 | return None; | ||
62 | } | ||
36 | } | 63 | } |
37 | 64 | ||
38 | let indent = node_indent(&file, comment.syntax())?; | 65 | let indent = node_indent(&file, comment.syntax())?; |
39 | let inserted = format!("\n{}{} $0", indent, prefix); | 66 | let inserted = format!("\n{}{} $0", indent, prefix); |
40 | let edit = TextEdit::insert(position.offset, inserted); | 67 | let delete = if remove_last_space { |
41 | 68 | TextRange::new(position.offset - TextSize::of(' '), position.offset) | |
69 | } else { | ||
70 | TextRange::empty(position.offset) | ||
71 | }; | ||
72 | let edit = TextEdit::replace(delete, inserted); | ||
42 | Some(edit) | 73 | Some(edit) |
43 | } | 74 | } |
44 | 75 | ||
@@ -75,10 +106,10 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> { | |||
75 | 106 | ||
76 | #[cfg(test)] | 107 | #[cfg(test)] |
77 | mod tests { | 108 | mod tests { |
78 | use test_utils::assert_eq_text; | 109 | use stdx::trim_indent; |
110 | use test_utils::{assert_eq_text, mark}; | ||
79 | 111 | ||
80 | use crate::mock_analysis::analysis_and_position; | 112 | use crate::mock_analysis::analysis_and_position; |
81 | use stdx::trim_indent; | ||
82 | 113 | ||
83 | fn apply_on_enter(before: &str) -> Option<String> { | 114 | fn apply_on_enter(before: &str) -> Option<String> { |
84 | let (analysis, position) = analysis_and_position(&before); | 115 | let (analysis, position) = analysis_and_position(&before); |
@@ -192,7 +223,7 @@ fn main() { | |||
192 | } | 223 | } |
193 | 224 | ||
194 | #[test] | 225 | #[test] |
195 | fn does_not_continue_end_of_code_comment() { | 226 | fn does_not_continue_end_of_line_comment() { |
196 | do_check_noop( | 227 | do_check_noop( |
197 | r" | 228 | r" |
198 | fn main() { | 229 | fn main() { |
@@ -202,4 +233,24 @@ fn main() { | |||
202 | ", | 233 | ", |
203 | ); | 234 | ); |
204 | } | 235 | } |
236 | |||
237 | #[test] | ||
238 | fn continues_end_of_line_comment_with_space() { | ||
239 | mark::check!(continues_end_of_line_comment_with_space); | ||
240 | do_check( | ||
241 | r#" | ||
242 | fn main() { | ||
243 | // Fix me <|> | ||
244 | let x = 1 + 1; | ||
245 | } | ||
246 | "#, | ||
247 | r#" | ||
248 | fn main() { | ||
249 | // Fix me | ||
250 | // $0 | ||
251 | let x = 1 + 1; | ||
252 | } | ||
253 | "#, | ||
254 | ); | ||
255 | } | ||
205 | } | 256 | } |
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 42f21289a..d880570d2 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -341,10 +341,10 @@ pub(crate) fn handle_workspace_symbol( | |||
341 | fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { | 341 | fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { |
342 | let mut res = Vec::new(); | 342 | let mut res = Vec::new(); |
343 | for nav in snap.analysis.symbol_search(query)? { | 343 | for nav in snap.analysis.symbol_search(query)? { |
344 | let container_name = nav.container_name().map(|v| v.to_string()); | 344 | let container_name = nav.container_name.as_ref().map(|v| v.to_string()); |
345 | let info = SymbolInformation { | 345 | let info = SymbolInformation { |
346 | name: nav.name().to_string(), | 346 | name: nav.name.to_string(), |
347 | kind: to_proto::symbol_kind(nav.kind()), | 347 | kind: to_proto::symbol_kind(nav.kind), |
348 | location: to_proto::location_from_nav(snap, nav)?, | 348 | location: to_proto::location_from_nav(snap, nav)?, |
349 | container_name, | 349 | container_name, |
350 | deprecated: None, | 350 | deprecated: None, |
@@ -434,7 +434,7 @@ pub(crate) fn handle_runnables( | |||
434 | let mut res = Vec::new(); | 434 | let mut res = Vec::new(); |
435 | for runnable in snap.analysis.runnables(file_id)? { | 435 | for runnable in snap.analysis.runnables(file_id)? { |
436 | if let Some(offset) = offset { | 436 | if let Some(offset) = offset { |
437 | if !runnable.nav.full_range().contains_inclusive(offset) { | 437 | if !runnable.nav.full_range.contains_inclusive(offset) { |
438 | continue; | 438 | continue; |
439 | } | 439 | } |
440 | } | 440 | } |
@@ -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( |
@@ -880,7 +875,7 @@ pub(crate) fn handle_code_lens( | |||
880 | } | 875 | } |
881 | 876 | ||
882 | let action = runnable.action(); | 877 | let action = runnable.action(); |
883 | let range = to_proto::range(&line_index, runnable.nav.range()); | 878 | let range = to_proto::range(&line_index, runnable.nav.focus_or_full_range()); |
884 | let r = to_proto::runnable(&snap, file_id, runnable)?; | 879 | let r = to_proto::runnable(&snap, file_id, runnable)?; |
885 | if snap.config.lens.run { | 880 | if snap.config.lens.run { |
886 | let lens = CodeLens { | 881 | let lens = CodeLens { |
@@ -1069,7 +1064,7 @@ pub(crate) fn handle_call_hierarchy_prepare( | |||
1069 | let RangeInfo { range: _, info: navs } = nav_info; | 1064 | let RangeInfo { range: _, info: navs } = nav_info; |
1070 | let res = navs | 1065 | let res = navs |
1071 | .into_iter() | 1066 | .into_iter() |
1072 | .filter(|it| it.kind() == SyntaxKind::FN_DEF) | 1067 | .filter(|it| it.kind == SyntaxKind::FN_DEF) |
1073 | .map(|it| to_proto::call_hierarchy_item(&snap, it)) | 1068 | .map(|it| to_proto::call_hierarchy_item(&snap, it)) |
1074 | .collect::<Result<Vec<_>>>()?; | 1069 | .collect::<Result<Vec<_>>>()?; |
1075 | 1070 | ||
@@ -1095,7 +1090,7 @@ pub(crate) fn handle_call_hierarchy_incoming( | |||
1095 | let mut res = vec![]; | 1090 | let mut res = vec![]; |
1096 | 1091 | ||
1097 | for call_item in call_items.into_iter() { | 1092 | for call_item in call_items.into_iter() { |
1098 | let file_id = call_item.target.file_id(); | 1093 | let file_id = call_item.target.file_id; |
1099 | let line_index = snap.analysis.file_line_index(file_id)?; | 1094 | let line_index = snap.analysis.file_line_index(file_id)?; |
1100 | let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; | 1095 | let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; |
1101 | res.push(CallHierarchyIncomingCall { | 1096 | res.push(CallHierarchyIncomingCall { |
@@ -1130,7 +1125,7 @@ pub(crate) fn handle_call_hierarchy_outgoing( | |||
1130 | let mut res = vec![]; | 1125 | let mut res = vec![]; |
1131 | 1126 | ||
1132 | for call_item in call_items.into_iter() { | 1127 | for call_item in call_items.into_iter() { |
1133 | let file_id = call_item.target.file_id(); | 1128 | let file_id = call_item.target.file_id; |
1134 | let line_index = snap.analysis.file_line_index(file_id)?; | 1129 | let line_index = snap.analysis.file_line_index(file_id)?; |
1135 | let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; | 1130 | let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; |
1136 | res.push(CallHierarchyOutgoingCall { | 1131 | res.push(CallHierarchyOutgoingCall { |
@@ -1226,13 +1221,13 @@ fn goto_location_command(snap: &GlobalStateSnapshot, nav: &NavigationTarget) -> | |||
1226 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; | 1221 | let link = to_proto::location_link(snap, None, nav.clone()).ok()?; |
1227 | to_value(link).ok()? | 1222 | to_value(link).ok()? |
1228 | } else { | 1223 | } else { |
1229 | let range = FileRange { file_id: nav.file_id(), range: nav.range() }; | 1224 | let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }; |
1230 | let location = to_proto::location(snap, range).ok()?; | 1225 | let location = to_proto::location(snap, range).ok()?; |
1231 | to_value(location).ok()? | 1226 | to_value(location).ok()? |
1232 | }; | 1227 | }; |
1233 | 1228 | ||
1234 | Some(Command { | 1229 | Some(Command { |
1235 | title: nav.name().to_string(), | 1230 | title: nav.name.to_string(), |
1236 | command: "rust-analyzer.gotoLocation".into(), | 1231 | command: "rust-analyzer.gotoLocation".into(), |
1237 | arguments: Some(vec![value]), | 1232 | arguments: Some(vec![value]), |
1238 | }) | 1233 | }) |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e60537fcd..687432ddb 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 { |
@@ -454,9 +497,9 @@ pub(crate) fn location_from_nav( | |||
454 | snap: &GlobalStateSnapshot, | 497 | snap: &GlobalStateSnapshot, |
455 | nav: NavigationTarget, | 498 | nav: NavigationTarget, |
456 | ) -> Result<lsp_types::Location> { | 499 | ) -> Result<lsp_types::Location> { |
457 | let url = url(snap, nav.file_id()); | 500 | let url = url(snap, nav.file_id); |
458 | let line_index = snap.analysis.file_line_index(nav.file_id())?; | 501 | let line_index = snap.analysis.file_line_index(nav.file_id)?; |
459 | let range = range(&line_index, nav.full_range()); | 502 | let range = range(&line_index, nav.full_range); |
460 | let loc = lsp_types::Location::new(url, range); | 503 | let loc = lsp_types::Location::new(url, range); |
461 | Ok(loc) | 504 | Ok(loc) |
462 | } | 505 | } |
@@ -488,12 +531,12 @@ fn location_info( | |||
488 | snap: &GlobalStateSnapshot, | 531 | snap: &GlobalStateSnapshot, |
489 | target: NavigationTarget, | 532 | target: NavigationTarget, |
490 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { | 533 | ) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { |
491 | let line_index = snap.analysis.file_line_index(target.file_id())?; | 534 | let line_index = snap.analysis.file_line_index(target.file_id)?; |
492 | 535 | ||
493 | let target_uri = url(snap, target.file_id()); | 536 | let target_uri = url(snap, target.file_id); |
494 | let target_range = range(&line_index, target.full_range()); | 537 | let target_range = range(&line_index, target.full_range); |
495 | let target_selection_range = | 538 | let target_selection_range = |
496 | target.focus_range().map(|it| range(&line_index, it)).unwrap_or(target_range); | 539 | target.focus_range.map(|it| range(&line_index, it)).unwrap_or(target_range); |
497 | Ok((target_uri, target_range, target_selection_range)) | 540 | Ok((target_uri, target_range, target_selection_range)) |
498 | } | 541 | } |
499 | 542 | ||
@@ -512,13 +555,7 @@ pub(crate) fn goto_definition_response( | |||
512 | let locations = targets | 555 | let locations = targets |
513 | .into_iter() | 556 | .into_iter() |
514 | .map(|nav| { | 557 | .map(|nav| { |
515 | location( | 558 | location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) |
516 | snap, | ||
517 | FileRange { | ||
518 | file_id: nav.file_id(), | ||
519 | range: nav.focus_range().unwrap_or(nav.range()), | ||
520 | }, | ||
521 | ) | ||
522 | }) | 559 | }) |
523 | .collect::<Result<Vec<_>>>()?; | 560 | .collect::<Result<Vec<_>>>()?; |
524 | Ok(locations.into()) | 561 | Ok(locations.into()) |
@@ -623,9 +660,9 @@ pub(crate) fn call_hierarchy_item( | |||
623 | snap: &GlobalStateSnapshot, | 660 | snap: &GlobalStateSnapshot, |
624 | target: NavigationTarget, | 661 | target: NavigationTarget, |
625 | ) -> Result<lsp_types::CallHierarchyItem> { | 662 | ) -> Result<lsp_types::CallHierarchyItem> { |
626 | let name = target.name().to_string(); | 663 | let name = target.name.to_string(); |
627 | let detail = target.description().map(|it| it.to_string()); | 664 | let detail = target.description.clone(); |
628 | let kind = symbol_kind(target.kind()); | 665 | let kind = symbol_kind(target.kind); |
629 | let (uri, range, selection_range) = location_info(snap, target)?; | 666 | let (uri, range, selection_range) = location_info(snap, target)?; |
630 | Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) | 667 | Ok(lsp_types::CallHierarchyItem { name, kind, tags: None, detail, uri, range, selection_range }) |
631 | } | 668 | } |
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 7fab7237b..978b463d5 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -373,3 +373,22 @@ Or it is possible to specify vars more granularly: | |||
373 | ``` | 373 | ``` |
374 | 374 | ||
375 | You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | 375 | You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. |
376 | |||
377 | ==== Compiler feedback from external commands | ||
378 | |||
379 | Instead of relying on the built-in `cargo check`, you can configure Code to run a command in the background and use the `$rustc-watch` problem matcher to generate inline error markers from its output. | ||
380 | |||
381 | To do this you need to create a new https://code.visualstudio.com/docs/editor/tasks[VS Code Task] and set `rust-analyzer.checkOnSave.enable: false` in preferences. | ||
382 | |||
383 | For example, if you want to run https://crates.io/crates/cargo-watch[`cargo watch`] instead, you might add the following to `.vscode/tasks.json`: | ||
384 | |||
385 | ```json | ||
386 | { | ||
387 | "label": "Watch", | ||
388 | "group": "build", | ||
389 | "type": "shell", | ||
390 | "command": "cargo watch", | ||
391 | "problemMatcher": "$rustc-watch", | ||
392 | "isBackground": true | ||
393 | } | ||
394 | ``` | ||