aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/ra_hir/src/code_model.rs94
-rw-r--r--crates/ra_hir/src/lib.rs13
-rw-r--r--crates/ra_hir/src/semantics.rs25
-rw-r--r--crates/ra_hir/src/source_analyzer.rs6
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs10
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs38
-rw-r--r--crates/ra_hir_ty/src/lib.rs11
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs13
-rw-r--r--crates/ra_ide/src/call_info.rs390
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs9
-rw-r--r--crates/ra_ide/src/completion/presentation.rs23
-rw-r--r--crates/ra_ide/src/display.rs63
-rw-r--r--crates/ra_ide/src/display/function_signature.rs321
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs81
-rw-r--r--crates/ra_ide/src/display/short_label.rs2
-rw-r--r--crates/ra_ide/src/file_structure.rs (renamed from crates/ra_ide/src/display/structure.rs)0
-rw-r--r--crates/ra_ide/src/goto_definition.rs2
-rw-r--r--crates/ra_ide/src/goto_implementation.rs2
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs2
-rw-r--r--crates/ra_ide/src/hover.rs144
-rw-r--r--crates/ra_ide/src/inlay_hints.rs80
-rw-r--r--crates/ra_ide/src/lib.rs53
-rw-r--r--crates/ra_ide/src/references.rs6
-rw-r--r--crates/ra_ide/src/runnables.rs60
-rw-r--r--crates/ra_ide/src/typing.rs1
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs67
-rw-r--r--crates/rust-analyzer/src/cli.rs8
-rw-r--r--crates/rust-analyzer/src/config.rs10
-rw-r--r--crates/rust-analyzer/src/handlers.rs39
-rw-r--r--crates/rust-analyzer/src/to_proto.rs111
-rw-r--r--docs/user/manual.adoc19
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]]
711name = "log" 711name = "log"
712version = "0.4.8" 712version = "0.4.11"
713source = "registry+https://github.com/rust-lang/crates.io-index" 713source = "registry+https://github.com/rust-lang/crates.io-index"
714checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 714checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
715dependencies = [ 715dependencies = [
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
2use std::sync::Arc; 2use std::{iter, sync::Arc};
3 3
4use arrayvec::ArrayVec; 4use arrayvec::ArrayVec;
5use either::Either; 5use either::Either;
@@ -12,6 +12,7 @@ use hir_def::{
12 import_map, 12 import_map,
13 per_ns::PerNs, 13 per_ns::PerNs,
14 resolver::{HasResolver, Resolver}, 14 resolver::{HasResolver, Resolver},
15 src::HasSource as _,
15 type_ref::{Mutability, TypeRef}, 16 type_ref::{Mutability, TypeRef},
16 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, 17 AdtId, AssocContainerId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule,
17 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, 18 ImplId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId,
@@ -25,8 +26,8 @@ use hir_expand::{
25use hir_ty::{ 26use hir_ty::{
26 autoderef, 27 autoderef,
27 display::{HirDisplayError, HirFormatter}, 28 display::{HirDisplayError, HirFormatter},
28 method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, 29 method_resolution, ApplicationTy, CallableDefId, Canonical, FnSig, GenericPredicate,
29 TraitEnvironment, Ty, TyDefId, TypeCtor, 30 InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
30}; 31};
31use ra_db::{CrateId, Edition, FileId}; 32use ra_db::{CrateId, Edition, FileId};
32use ra_prof::profile; 33use ra_prof::profile;
@@ -40,7 +41,7 @@ use stdx::impl_from;
40use crate::{ 41use crate::{
41 db::{DefDatabase, HirDatabase}, 42 db::{DefDatabase, HirDatabase},
42 has_source::HasSource, 43 has_source::HasSource,
43 CallableDefId, HirDisplay, InFile, Name, 44 HirDisplay, InFile, Name,
44}; 45};
45 46
46/// hir::Crate describes a single crate. It's the main interface with which 47/// hir::Crate describes a single crate. It's the main interface with which
@@ -1168,6 +1169,12 @@ impl Type {
1168 Type::new(db, krate, def, ty) 1169 Type::new(db, krate, def, ty)
1169 } 1170 }
1170 1171
1172 pub fn is_unit(&self) -> bool {
1173 matches!(
1174 self.ty.value,
1175 Ty::Apply(ApplicationTy { ctor: TypeCtor::Tuple { cardinality: 0 }, .. })
1176 )
1177 }
1171 pub fn is_bool(&self) -> bool { 1178 pub fn is_bool(&self) -> bool {
1172 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })) 1179 matches!(self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. }))
1173 } 1180 }
@@ -1225,9 +1232,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)]
1529pub struct Callable {
1530 ty: Type,
1531 sig: FnSig,
1532 def: Option<CallableDefId>,
1533 pub(crate) is_bound_method: bool,
1534}
1535
1536pub enum CallableKind {
1537 Function(Function),
1538 TupleStruct(Struct),
1539 TupleEnumVariant(EnumVariant),
1540 Closure,
1541}
1542
1543impl 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)]
1517pub enum ScopeDef { 1597pub enum ScopeDef {
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index cf7134923..31f3241c9 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -32,10 +32,10 @@ mod has_source;
32 32
33pub use crate::{ 33pub use crate::{
34 code_model::{ 34 code_model::{
35 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, 35 Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Callable, CallableKind, Const,
36 DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function, GenericDef, HasAttrs, 36 Crate, CrateDependency, DefWithBody, Docs, Enum, EnumVariant, Field, FieldSource, Function,
37 HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, 37 GenericDef, HasAttrs, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef,
38 Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, 38 Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility,
39 }, 39 },
40 has_source::HasSource, 40 has_source::HasSource,
41 semantics::{original_range, PathResolution, Semantics, SemanticsScope}, 41 semantics::{original_range, PathResolution, Semantics, SemanticsScope},
@@ -52,7 +52,8 @@ pub use hir_def::{
52 type_ref::Mutability, 52 type_ref::Mutability,
53}; 53};
54pub use hir_expand::{ 54pub use hir_expand::{
55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, 55 hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc,
56 MacroDefId, /* FIXME */
56 MacroFile, Origin, 57 MacroFile, Origin,
57}; 58};
58pub use hir_ty::{display::HirDisplay, CallableDefId}; 59pub use hir_ty::display::HirDisplay;
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 155b666d7..f5283ab22 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -6,7 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use hir_def::{ 7use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, TraitId, VariantId, 9 AsMacroCall, FunctionId, TraitId, VariantId,
10}; 10};
11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; 11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
@@ -24,8 +24,8 @@ use crate::{
24 diagnostics::Diagnostic, 24 diagnostics::Diagnostic,
25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 25 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, 26 source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27 AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, 27 AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module,
28 Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, 28 ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
29}; 29};
30use resolver::TypeNs; 30use resolver::TypeNs;
31 31
@@ -197,7 +197,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
197 } 197 }
198 198
199 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 199 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
200 self.imp.resolve_method_call(call) 200 self.imp.resolve_method_call(call).map(Function::from)
201 }
202
203 pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
204 self.imp.resolve_method_call_as_callable(call)
201 } 205 }
202 206
203 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { 207 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
@@ -385,10 +389,21 @@ impl<'db> SemanticsImpl<'db> {
385 self.analyze(param.syntax()).type_of_self(self.db, &param) 389 self.analyze(param.syntax()).type_of_self(self.db, &param)
386 } 390 }
387 391
388 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 392 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
389 self.analyze(call.syntax()).resolve_method_call(self.db, call) 393 self.analyze(call.syntax()).resolve_method_call(self.db, call)
390 } 394 }
391 395
396 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
397 // FIXME: this erases Substs
398 let func = self.resolve_method_call(call)?;
399 let ty = self.db.value_ty(func.into());
400 let resolver = self.analyze(call.syntax()).resolver;
401 let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?;
402 let mut res = ty.as_callable(self.db)?;
403 res.is_bound_method = true;
404 Some(res)
405 }
406
392 fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> { 407 fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
393 self.analyze(field.syntax()).resolve_field(self.db, field) 408 self.analyze(field.syntax()).resolve_field(self.db, field)
394 } 409 }
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index ecb54f653..86a47a9e5 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -14,7 +14,7 @@ use hir_def::{
14 }, 14 },
15 expr::{ExprId, Pat, PatId}, 15 expr::{ExprId, Pat, PatId},
16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, 16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
17 AsMacroCall, DefWithBodyId, FieldId, LocalFieldId, VariantId, 17 AsMacroCall, DefWithBodyId, FieldId, FunctionId, LocalFieldId, VariantId,
18}; 18};
19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
20use hir_ty::{ 20use hir_ty::{
@@ -142,9 +142,9 @@ impl SourceAnalyzer {
142 &self, 142 &self,
143 db: &dyn HirDatabase, 143 db: &dyn HirDatabase,
144 call: &ast::MethodCallExpr, 144 call: &ast::MethodCallExpr,
145 ) -> Option<Function> { 145 ) -> Option<FunctionId> {
146 let expr_id = self.expr_id(db, &call.clone().into())?; 146 let expr_id = self.expr_id(db, &call.clone().into())?;
147 self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) 147 self.infer.as_ref()?.method_resolution(expr_id)
148 } 148 }
149 149
150 pub(crate) fn resolve_field( 150 pub(crate) fn resolve_field(
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index 19692e70c..dbfa7fccb 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -226,7 +226,15 @@ impl CrateDefMap {
226 match enum_data.variant(&segment) { 226 match enum_data.variant(&segment) {
227 Some(local_id) => { 227 Some(local_id) => {
228 let variant = EnumVariantId { parent: e, local_id }; 228 let variant = EnumVariantId { parent: e, local_id };
229 PerNs::both(variant.into(), variant.into(), Visibility::Public) 229 match &*enum_data.variants[local_id].variant_data {
230 crate::adt::VariantData::Record(_) => {
231 PerNs::types(variant.into(), Visibility::Public)
232 }
233 crate::adt::VariantData::Tuple(_)
234 | crate::adt::VariantData::Unit => {
235 PerNs::both(variant.into(), variant.into(), Visibility::Public)
236 }
237 }
230 } 238 }
231 None => { 239 None => {
232 return ResolvePathResult::with( 240 return ResolvePathResult::with(
diff --git a/crates/ra_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#"
554fn 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(&macro_call)?;
114 Some(macro_def.to_nav(db))
115 }
116 } { 112 } {
117 Some((func_target, name_ref.syntax().text_range())) 113 Some((func_target, name_ref.syntax().text_range()))
118 } else { 114 } else {
@@ -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
2use hir::Semantics; 2use either::Either;
3use hir::{Docs, HirDisplay, Semantics, Type};
3use ra_ide_db::RootDatabase; 4use ra_ide_db::RootDatabase;
4use ra_syntax::{ 5use 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};
9use stdx::format_to;
8use test_utils::mark; 10use test_utils::mark;
9 11
10use crate::{FilePosition, FunctionSignature}; 12use 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)]
15pub struct CallInfo { 17pub 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
24impl 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)?;
31pub(crate) struct ActiveParameter {
32 /// FIXME: should be `Type` and `Name
33 pub(crate) ty: String,
34 pub(crate) name: String,
35}
36 51
37impl 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
47fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { 108fn 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(&macro_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(); 144pub(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( 149impl 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)]
122pub(crate) enum FnCallNode { 171pub(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
128impl FnCallNode { 176impl 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
183impl CallInfo {
184 fn into_active_parameter(self) -> Option<ActiveParameter> {
185 let idx = self.active_parameter?;
186 let ty = self.signature.parameter_types.get(idx)?.clone();
187 let name = self.signature.parameter_names.get(idx)?.clone();
188 let res = ActiveParameter { ty, name };
189 Some(res)
190 }
191}
192
193#[cfg(test)] 226#[cfg(test)]
194mod tests { 227mod 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
296fn bar() { foo(<|>3, ); } 327fn 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 {}
312fn bar() { foo(<|>); } 341fn 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#"
326struct F; impl F { pub fn new() { F{}} } 354struct F;
327fn bar() {let _ : F = F::new(<|>);} 355impl F { pub fn new() { } }
356fn 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#"
359struct S; 390struct S;
360impl S { pub fn do_it(&self, x: i32) {} } 391impl S {
392 fn foo(&self, x: i32) {}
393}
361 394
362fn bar() { 395fn 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#"
408struct S;
409impl S {
410 fn foo(&self, x: i32) {}
365} 411}
412
413fn 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
552struct TS(u32, i32); 600struct S(u32, i32);
553fn main() { 601fn 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#"
570struct TS<T>(T); 618struct S<T>(T);
571fn main() { 619fn 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#"
586struct TS { x: u32, y: i32 }
587fn main() {
588 let s = TS(<|>);
589}
590"#,
591 expect![[""]],
592 );
593 }
594
595 #[test]
596 fn works_for_enum_variants() { 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#"
660struct S { x: u32, y: i32 }
661fn 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#"
625enum E { 673enum 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 694macro_rules! id { ($($tt:tt)*) => { $($tt)* } }
647macro_rules! foo { 695fn foo() { }
648 () => {} 696id! {
649} 697 fn bar() { foo(<|>); }
650
651fn 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#"
668macro_rules! id { ($($tt:tt)*) => { $($tt)* } } 711struct S;
669fn foo() { } 712fn foo(s: S) -> i32 { 92 }
670id! { 713fn 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#"
728fn 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
49pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 49pub(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
4mod function_signature;
5mod navigation_target; 4mod navigation_target;
6mod structure;
7mod short_label; 5mod short_label;
8 6
9use ra_syntax::{ 7use ra_syntax::{
@@ -11,15 +9,49 @@ use ra_syntax::{
11 SyntaxKind::{ATTR, COMMENT}, 9 SyntaxKind::{ATTR, COMMENT},
12}; 10};
13 11
14pub use function_signature::FunctionSignature; 12use ast::VisibilityOwner;
15pub use navigation_target::NavigationTarget; 13use stdx::format_to;
16pub use structure::{file_structure, StructureNode};
17 14
15pub use navigation_target::NavigationTarget;
18pub(crate) use navigation_target::{ToNav, TryToNav}; 16pub(crate) use navigation_target::{ToNav, TryToNav};
19pub(crate) use short_label::ShortLabel; 17pub(crate) use short_label::ShortLabel;
20 18
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 19pub(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
25pub(crate) fn const_label(node: &ast::ConstDef) -> String { 57pub(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
47pub(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
56pub(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
64pub(crate) fn macro_label(node: &ast::MacroCall) -> String { 79pub(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)
5use std::{
6 convert::From,
7 fmt::{self, Display},
8};
9
10use hir::{Docs, Documentation, HasSource, HirDisplay};
11use ra_ide_db::RootDatabase;
12use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
13use stdx::{split_delim, SepBy};
14
15use crate::display::{generic_parameters, where_predicates};
16
17#[derive(Debug)]
18pub enum CallableKind {
19 Function,
20 StructConstructor,
21 VariantConstructor,
22 Macro,
23}
24
25/// Contains information about a function signature
26#[derive(Debug)]
27pub 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)]
54pub 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
63impl 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
175impl 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
273impl 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)]
24pub struct NavigationTarget { 24pub 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
36pub(crate) trait ToNav { 49pub(crate) trait ToNav {
@@ -42,44 +55,9 @@ pub(crate) trait TryToNav {
42} 55}
43 56
44impl NavigationTarget { 57impl 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
10impl ShortLabel for ast::FnDef { 10impl 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
133fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { 133fn 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 @@
1use hir::{Adt, HirDisplay, Semantics, Type}; 1use hir::{Adt, Callable, HirDisplay, Semantics, Type};
2use ra_ide_db::RootDatabase; 2use ra_ide_db::RootDatabase;
3use ra_prof::profile; 3use ra_prof::profile;
4use ra_syntax::{ 4use 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
9use crate::{FileId, FunctionSignature};
10use stdx::to_lower_snake_case; 8use stdx::to_lower_snake_case;
11 9
10use crate::FileId;
11use ast::NameOwner;
12use either::Either;
13
12#[derive(Clone, Debug, PartialEq, Eq)] 14#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct InlayHintsConfig { 15pub 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, &param_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
251fn should_show_param_name_hint( 256fn 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
277fn is_argument_similar_to_param_name( 282fn 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
321fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { 326fn 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
20mod markup; 20mod markup;
21mod prime_caches; 21mod prime_caches;
22mod status; 22mod display;
23
24mod call_hierarchy;
25mod call_info;
23mod completion; 26mod completion;
24mod runnables; 27mod diagnostics;
28mod expand_macro;
29mod extend_selection;
30mod file_structure;
31mod folding_ranges;
25mod goto_definition; 32mod goto_definition;
26mod goto_type_definition;
27mod goto_implementation; 33mod goto_implementation;
28mod extend_selection; 34mod goto_type_definition;
29mod hover; 35mod hover;
30mod call_hierarchy; 36mod inlay_hints;
31mod call_info; 37mod join_lines;
32mod syntax_highlighting; 38mod matching_brace;
33mod parent_module; 39mod parent_module;
34mod references; 40mod references;
35mod diagnostics; 41mod runnables;
42mod ssr;
43mod status;
44mod syntax_highlighting;
36mod syntax_tree; 45mod syntax_tree;
37mod folding_ranges;
38mod join_lines;
39mod typing; 46mod typing;
40mod matching_brace;
41mod display;
42mod inlay_hints;
43mod expand_macro;
44mod ssr;
45 47
46use std::sync::Arc; 48use 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#"
565mod foo { 568mod 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
44pub(crate) fn on_char_typed( 43pub(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};
12use ra_text_edit::TextEdit; 12use ra_text_edit::TextEdit;
13use 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// ----
14pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { 35pub(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)]
77mod tests { 108mod 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"
198fn main() { 229fn 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#"
242fn main() {
243 // Fix me <|>
244 let x = 1 + 1;
245}
246"#,
247 r#"
248fn 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;
10use std::io::Read; 10use std::io::Read;
11 11
12use anyhow::Result; 12use anyhow::Result;
13use ra_ide::{file_structure, Analysis}; 13use ra_ide::Analysis;
14use ra_prof::profile; 14use ra_prof::profile;
15use ra_syntax::{AstNode, SourceFile}; 15use ra_syntax::{AstNode, SourceFile};
16 16
@@ -48,8 +48,10 @@ pub fn parse(no_dump: bool) -> Result<()> {
48} 48}
49 49
50pub fn symbols() -> Result<()> { 50pub 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
132impl Config { 133impl 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
573pub(crate) fn handle_hover( 568pub(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};
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::{FileId, FileRange}; 5use ra_db::{FileId, FileRange};
6use ra_ide::{ 6use ra_ide::{
7 Assist, AssistKind, CompletionItem, CompletionItemKind, Documentation, FileSystemEdit, Fold, 7 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation,
8 FoldKind, FunctionSignature, Highlight, HighlightModifier, HighlightTag, HighlightedRange, 8 FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
9 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, 9 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
10 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, 10 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
11}; 11};
@@ -219,29 +219,72 @@ pub(crate) fn completion_item(
219 res 219 res
220} 220}
221 221
222pub(crate) fn signature_information( 222pub(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
247pub(crate) fn inlay_int(line_index: &LineIndex, inlay_hint: InlayHint) -> lsp_ext::InlayHint { 290pub(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
375You 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. 375You 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
379Instead 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
381To 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
383For 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```