diff options
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r-- | crates/ra_ide/src/call_hierarchy.rs | 13 | ||||
-rw-r--r-- | crates/ra_ide/src/call_info.rs | 390 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_trait_impl.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 23 | ||||
-rw-r--r-- | crates/ra_ide/src/display.rs | 63 | ||||
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 321 | ||||
-rw-r--r-- | crates/ra_ide/src/display/navigation_target.rs | 81 | ||||
-rw-r--r-- | crates/ra_ide/src/display/short_label.rs | 2 | ||||
-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.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_implementation.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/goto_type_definition.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 144 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 80 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 53 | ||||
-rw-r--r-- | crates/ra_ide/src/references.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide/src/runnables.rs | 60 | ||||
-rw-r--r-- | crates/ra_ide/src/typing.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide/src/typing/on_enter.rs | 67 |
19 files changed, 538 insertions, 781 deletions
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs index cb7e62cd6..c28af8ab3 100644 --- a/crates/ra_ide/src/call_hierarchy.rs +++ b/crates/ra_ide/src/call_hierarchy.rs | |||
@@ -95,9 +95,9 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
95 | if let Some(func_target) = match &call_node { | 95 | if let Some(func_target) = match &call_node { |
96 | FnCallNode::CallExpr(expr) => { | 96 | FnCallNode::CallExpr(expr) => { |
97 | //FIXME: Type::as_callable is broken | 97 | //FIXME: Type::as_callable is broken |
98 | let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; | 98 | let callable = sema.type_of_expr(&expr.expr()?)?.as_callable(db)?; |
99 | match callable_def { | 99 | match callable.kind() { |
100 | hir::CallableDefId::FunctionId(it) => { | 100 | hir::CallableKind::Function(it) => { |
101 | let fn_def: hir::Function = it.into(); | 101 | let fn_def: hir::Function = it.into(); |
102 | let nav = fn_def.to_nav(db); | 102 | let nav = fn_def.to_nav(db); |
103 | Some(nav) | 103 | Some(nav) |
@@ -109,10 +109,6 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
109 | let function = sema.resolve_method_call(&expr)?; | 109 | let function = sema.resolve_method_call(&expr)?; |
110 | Some(function.to_nav(db)) | 110 | Some(function.to_nav(db)) |
111 | } | 111 | } |
112 | FnCallNode::MacroCallExpr(macro_call) => { | ||
113 | let macro_def = sema.resolve_macro_call(¯o_call)?; | ||
114 | Some(macro_def.to_nav(db)) | ||
115 | } | ||
116 | } { | 112 | } { |
117 | Some((func_target, name_ref.syntax().text_range())) | 113 | Some((func_target, name_ref.syntax().text_range())) |
118 | } else { | 114 | } else { |
@@ -158,7 +154,8 @@ mod tests { | |||
158 | let nav = navs.pop().unwrap(); | 154 | let nav = navs.pop().unwrap(); |
159 | nav.assert_match(expected); | 155 | nav.assert_match(expected); |
160 | 156 | ||
161 | let item_pos = FilePosition { file_id: nav.file_id(), offset: nav.range().start() }; | 157 | let item_pos = |
158 | FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() }; | ||
162 | let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); | 159 | let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap(); |
163 | assert_eq!(incoming_calls.len(), expected_incoming.len()); | 160 | assert_eq!(incoming_calls.len(), expected_incoming.len()); |
164 | 161 | ||
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index 1fe1c21de..14980afdd 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs | |||
@@ -1,20 +1,42 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use hir::Semantics; | 2 | use either::Either; |
3 | use hir::{Docs, HirDisplay, Semantics, Type}; | ||
3 | use ra_ide_db::RootDatabase; | 4 | use ra_ide_db::RootDatabase; |
4 | use ra_syntax::{ | 5 | use ra_syntax::{ |
5 | ast::{self, ArgListOwner}, | 6 | ast::{self, ArgListOwner}, |
6 | match_ast, AstNode, SyntaxNode, SyntaxToken, | 7 | match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, |
7 | }; | 8 | }; |
9 | use stdx::format_to; | ||
8 | use test_utils::mark; | 10 | use test_utils::mark; |
9 | 11 | ||
10 | use crate::{FilePosition, FunctionSignature}; | 12 | use crate::FilePosition; |
11 | 13 | ||
12 | /// Contains information about a call site. Specifically the | 14 | /// Contains information about a call site. Specifically the |
13 | /// `FunctionSignature`and current parameter. | 15 | /// `FunctionSignature`and current parameter. |
14 | #[derive(Debug)] | 16 | #[derive(Debug)] |
15 | pub struct CallInfo { | 17 | pub struct CallInfo { |
16 | pub signature: FunctionSignature, | 18 | pub doc: Option<String>, |
19 | pub signature: String, | ||
17 | pub active_parameter: Option<usize>, | 20 | pub active_parameter: Option<usize>, |
21 | parameters: Vec<TextRange>, | ||
22 | } | ||
23 | |||
24 | impl CallInfo { | ||
25 | pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ { | ||
26 | self.parameters.iter().map(move |&it| &self.signature[it]) | ||
27 | } | ||
28 | pub fn parameter_ranges(&self) -> &[TextRange] { | ||
29 | &self.parameters | ||
30 | } | ||
31 | fn push_param(&mut self, param: &str) { | ||
32 | if !self.signature.ends_with('(') { | ||
33 | self.signature.push_str(", "); | ||
34 | } | ||
35 | let start = TextSize::of(&self.signature); | ||
36 | self.signature.push_str(param); | ||
37 | let end = TextSize::of(&self.signature); | ||
38 | self.parameters.push(TextRange::new(start, end)) | ||
39 | } | ||
18 | } | 40 | } |
19 | 41 | ||
20 | /// Computes parameter information for the given call expression. | 42 | /// Computes parameter information for the given call expression. |
@@ -24,105 +46,131 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
24 | let file = file.syntax(); | 46 | let file = file.syntax(); |
25 | let token = file.token_at_offset(position.offset).next()?; | 47 | let token = file.token_at_offset(position.offset).next()?; |
26 | let token = sema.descend_into_macros(token); | 48 | let token = sema.descend_into_macros(token); |
27 | call_info_for_token(&sema, token) | ||
28 | } | ||
29 | 49 | ||
30 | #[derive(Debug)] | 50 | let (callable, active_parameter) = call_info_impl(&sema, token)?; |
31 | pub(crate) struct ActiveParameter { | ||
32 | /// FIXME: should be `Type` and `Name | ||
33 | pub(crate) ty: String, | ||
34 | pub(crate) name: String, | ||
35 | } | ||
36 | 51 | ||
37 | impl ActiveParameter { | 52 | let mut res = |
38 | pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { | 53 | CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter }; |
39 | call_info(db, position)?.into_active_parameter() | 54 | |
55 | match callable.kind() { | ||
56 | hir::CallableKind::Function(func) => { | ||
57 | res.doc = func.docs(db).map(|it| it.as_str().to_string()); | ||
58 | format_to!(res.signature, "fn {}", func.name(db)); | ||
59 | } | ||
60 | hir::CallableKind::TupleStruct(strukt) => { | ||
61 | res.doc = strukt.docs(db).map(|it| it.as_str().to_string()); | ||
62 | format_to!(res.signature, "struct {}", strukt.name(db)); | ||
63 | } | ||
64 | hir::CallableKind::TupleEnumVariant(variant) => { | ||
65 | res.doc = variant.docs(db).map(|it| it.as_str().to_string()); | ||
66 | format_to!( | ||
67 | res.signature, | ||
68 | "enum {}::{}", | ||
69 | variant.parent_enum(db).name(db), | ||
70 | variant.name(db) | ||
71 | ); | ||
72 | } | ||
73 | hir::CallableKind::Closure => (), | ||
40 | } | 74 | } |
41 | 75 | ||
42 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { | 76 | res.signature.push('('); |
43 | call_info_for_token(sema, token)?.into_active_parameter() | 77 | { |
78 | if let Some(self_param) = callable.receiver_param(db) { | ||
79 | format_to!(res.signature, "{}", self_param) | ||
80 | } | ||
81 | let mut buf = String::new(); | ||
82 | for (pat, ty) in callable.params(db) { | ||
83 | buf.clear(); | ||
84 | if let Some(pat) = pat { | ||
85 | match pat { | ||
86 | Either::Left(_self) => format_to!(buf, "self: "), | ||
87 | Either::Right(pat) => format_to!(buf, "{}: ", pat), | ||
88 | } | ||
89 | } | ||
90 | format_to!(buf, "{}", ty.display(db)); | ||
91 | res.push_param(&buf); | ||
92 | } | ||
44 | } | 93 | } |
94 | res.signature.push(')'); | ||
95 | |||
96 | match callable.kind() { | ||
97 | hir::CallableKind::Function(_) | hir::CallableKind::Closure => { | ||
98 | let ret_type = callable.return_type(); | ||
99 | if !ret_type.is_unit() { | ||
100 | format_to!(res.signature, " -> {}", ret_type.display(db)); | ||
101 | } | ||
102 | } | ||
103 | hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {} | ||
104 | } | ||
105 | Some(res) | ||
45 | } | 106 | } |
46 | 107 | ||
47 | fn call_info_for_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<CallInfo> { | 108 | fn call_info_impl( |
109 | sema: &Semantics<RootDatabase>, | ||
110 | token: SyntaxToken, | ||
111 | ) -> Option<(hir::Callable, Option<usize>)> { | ||
48 | // Find the calling expression and it's NameRef | 112 | // Find the calling expression and it's NameRef |
49 | let calling_node = FnCallNode::with_node(&token.parent())?; | 113 | let calling_node = FnCallNode::with_node(&token.parent())?; |
50 | 114 | ||
51 | let signature = match &calling_node { | 115 | let callable = match &calling_node { |
52 | FnCallNode::CallExpr(call) => { | 116 | FnCallNode::CallExpr(call) => sema.type_of_expr(&call.expr()?)?.as_callable(sema.db)?, |
53 | //FIXME: Type::as_callable is broken | 117 | FnCallNode::MethodCallExpr(call) => sema.resolve_method_call_as_callable(call)?, |
54 | let callable_def = sema.type_of_expr(&call.expr()?)?.as_callable()?; | 118 | }; |
55 | match callable_def { | 119 | let active_param = if let Some(arg_list) = calling_node.arg_list() { |
56 | hir::CallableDefId::FunctionId(it) => { | 120 | // Number of arguments specified at the call site |
57 | let fn_def = it.into(); | 121 | let num_args_at_callsite = arg_list.args().count(); |
58 | FunctionSignature::from_hir(sema.db, fn_def) | 122 | |
59 | } | 123 | let arg_list_range = arg_list.syntax().text_range(); |
60 | hir::CallableDefId::StructId(it) => { | 124 | if !arg_list_range.contains_inclusive(token.text_range().start()) { |
61 | FunctionSignature::from_struct(sema.db, it.into())? | 125 | mark::hit!(call_info_bad_offset); |
62 | } | 126 | return None; |
63 | hir::CallableDefId::EnumVariantId(it) => { | ||
64 | FunctionSignature::from_enum_variant(sema.db, it.into())? | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | FnCallNode::MethodCallExpr(method_call) => { | ||
69 | let function = sema.resolve_method_call(&method_call)?; | ||
70 | FunctionSignature::from_hir(sema.db, function) | ||
71 | } | ||
72 | FnCallNode::MacroCallExpr(macro_call) => { | ||
73 | let macro_def = sema.resolve_macro_call(¯o_call)?; | ||
74 | FunctionSignature::from_macro(sema.db, macro_def)? | ||
75 | } | 127 | } |
128 | let param = std::cmp::min( | ||
129 | num_args_at_callsite, | ||
130 | arg_list | ||
131 | .args() | ||
132 | .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start()) | ||
133 | .count(), | ||
134 | ); | ||
135 | |||
136 | Some(param) | ||
137 | } else { | ||
138 | None | ||
76 | }; | 139 | }; |
140 | Some((callable, active_param)) | ||
141 | } | ||
77 | 142 | ||
78 | // If we have a calling expression let's find which argument we are on | 143 | #[derive(Debug)] |
79 | let num_params = signature.parameters.len(); | 144 | pub(crate) struct ActiveParameter { |
80 | 145 | pub(crate) ty: Type, | |
81 | let active_parameter = match num_params { | 146 | pub(crate) name: String, |
82 | 0 => None, | 147 | } |
83 | 1 if signature.has_self_param => None, | ||
84 | 1 => Some(0), | ||
85 | _ => { | ||
86 | if let Some(arg_list) = calling_node.arg_list() { | ||
87 | // Number of arguments specified at the call site | ||
88 | let num_args_at_callsite = arg_list.args().count(); | ||
89 | |||
90 | let arg_list_range = arg_list.syntax().text_range(); | ||
91 | if !arg_list_range.contains_inclusive(token.text_range().start()) { | ||
92 | mark::hit!(call_info_bad_offset); | ||
93 | return None; | ||
94 | } | ||
95 | 148 | ||
96 | let mut param = std::cmp::min( | 149 | impl ActiveParameter { |
97 | num_args_at_callsite, | 150 | pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> { |
98 | arg_list | 151 | let sema = Semantics::new(db); |
99 | .args() | 152 | let file = sema.parse(position.file_id); |
100 | .take_while(|arg| { | 153 | let file = file.syntax(); |
101 | arg.syntax().text_range().end() <= token.text_range().start() | 154 | let token = file.token_at_offset(position.offset).next()?; |
102 | }) | 155 | let token = sema.descend_into_macros(token); |
103 | .count(), | 156 | Self::at_token(&sema, token) |
104 | ); | 157 | } |
105 | |||
106 | // If we are in a method account for `self` | ||
107 | if signature.has_self_param { | ||
108 | param += 1; | ||
109 | } | ||
110 | 158 | ||
111 | Some(param) | 159 | pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> { |
112 | } else { | 160 | let (signature, active_parameter) = call_info_impl(&sema, token)?; |
113 | None | ||
114 | } | ||
115 | } | ||
116 | }; | ||
117 | 161 | ||
118 | Some(CallInfo { signature, active_parameter }) | 162 | let idx = active_parameter?; |
163 | let mut params = signature.params(sema.db); | ||
164 | let (pat, ty) = params.swap_remove(idx); | ||
165 | let name = pat?.to_string(); | ||
166 | Some(ActiveParameter { ty, name }) | ||
167 | } | ||
119 | } | 168 | } |
120 | 169 | ||
121 | #[derive(Debug)] | 170 | #[derive(Debug)] |
122 | pub(crate) enum FnCallNode { | 171 | pub(crate) enum FnCallNode { |
123 | CallExpr(ast::CallExpr), | 172 | CallExpr(ast::CallExpr), |
124 | MethodCallExpr(ast::MethodCallExpr), | 173 | MethodCallExpr(ast::MethodCallExpr), |
125 | MacroCallExpr(ast::MacroCall), | ||
126 | } | 174 | } |
127 | 175 | ||
128 | impl FnCallNode { | 176 | impl FnCallNode { |
@@ -138,7 +186,6 @@ impl FnCallNode { | |||
138 | } | 186 | } |
139 | Some(FnCallNode::MethodCallExpr(it)) | 187 | Some(FnCallNode::MethodCallExpr(it)) |
140 | }, | 188 | }, |
141 | ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)), | ||
142 | _ => None, | 189 | _ => None, |
143 | } | 190 | } |
144 | } | 191 | } |
@@ -150,7 +197,6 @@ impl FnCallNode { | |||
150 | match node { | 197 | match node { |
151 | ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), | 198 | ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)), |
152 | ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), | 199 | ast::MethodCallExpr(it) => Some(FnCallNode::MethodCallExpr(it)), |
153 | ast::MacroCall(it) => Some(FnCallNode::MacroCallExpr(it)), | ||
154 | _ => None, | 200 | _ => None, |
155 | } | 201 | } |
156 | } | 202 | } |
@@ -166,8 +212,6 @@ impl FnCallNode { | |||
166 | FnCallNode::MethodCallExpr(call_expr) => { | 212 | FnCallNode::MethodCallExpr(call_expr) => { |
167 | call_expr.syntax().children().filter_map(ast::NameRef::cast).next() | 213 | call_expr.syntax().children().filter_map(ast::NameRef::cast).next() |
168 | } | 214 | } |
169 | |||
170 | FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(), | ||
171 | } | 215 | } |
172 | } | 216 | } |
173 | 217 | ||
@@ -175,21 +219,10 @@ impl FnCallNode { | |||
175 | match self { | 219 | match self { |
176 | FnCallNode::CallExpr(expr) => expr.arg_list(), | 220 | FnCallNode::CallExpr(expr) => expr.arg_list(), |
177 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), | 221 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), |
178 | FnCallNode::MacroCallExpr(_) => None, | ||
179 | } | 222 | } |
180 | } | 223 | } |
181 | } | 224 | } |
182 | 225 | ||
183 | impl CallInfo { | ||
184 | fn into_active_parameter(self) -> Option<ActiveParameter> { | ||
185 | let idx = self.active_parameter?; | ||
186 | let ty = self.signature.parameter_types.get(idx)?.clone(); | ||
187 | let name = self.signature.parameter_names.get(idx)?.clone(); | ||
188 | let res = ActiveParameter { ty, name }; | ||
189 | Some(res) | ||
190 | } | ||
191 | } | ||
192 | |||
193 | #[cfg(test)] | 226 | #[cfg(test)] |
194 | mod tests { | 227 | mod tests { |
195 | use expect::{expect, Expect}; | 228 | use expect::{expect, Expect}; |
@@ -202,20 +235,18 @@ mod tests { | |||
202 | let call_info = analysis.call_info(position).unwrap(); | 235 | let call_info = analysis.call_info(position).unwrap(); |
203 | let actual = match call_info { | 236 | let actual = match call_info { |
204 | Some(call_info) => { | 237 | Some(call_info) => { |
205 | let docs = match &call_info.signature.doc { | 238 | let docs = match &call_info.doc { |
206 | None => "".to_string(), | 239 | None => "".to_string(), |
207 | Some(docs) => format!("{}\n------\n", docs.as_str()), | 240 | Some(docs) => format!("{}\n------\n", docs.as_str()), |
208 | }; | 241 | }; |
209 | let params = call_info | 242 | let params = call_info |
210 | .signature | 243 | .parameter_labels() |
211 | .parameters | ||
212 | .iter() | ||
213 | .enumerate() | 244 | .enumerate() |
214 | .map(|(i, param)| { | 245 | .map(|(i, param)| { |
215 | if Some(i) == call_info.active_parameter { | 246 | if Some(i) == call_info.active_parameter { |
216 | format!("<{}>", param) | 247 | format!("<{}>", param) |
217 | } else { | 248 | } else { |
218 | param.clone() | 249 | param.to_string() |
219 | } | 250 | } |
220 | }) | 251 | }) |
221 | .collect::<Vec<_>>() | 252 | .collect::<Vec<_>>() |
@@ -296,10 +327,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | |||
296 | fn bar() { foo(<|>3, ); } | 327 | fn bar() { foo(<|>3, ); } |
297 | "#, | 328 | "#, |
298 | expect![[r#" | 329 | expect![[r#" |
299 | fn foo<T, U: Copy + Display>(x: T, y: U) -> u32 | 330 | fn foo(x: i32, y: {unknown}) -> u32 |
300 | where T: Copy + Display, | 331 | (<x: i32>, y: {unknown}) |
301 | U: Debug | ||
302 | (<x: T>, y: U) | ||
303 | "#]], | 332 | "#]], |
304 | ); | 333 | ); |
305 | } | 334 | } |
@@ -312,8 +341,7 @@ fn foo<T>() -> T where T: Copy + Display {} | |||
312 | fn bar() { foo(<|>); } | 341 | fn bar() { foo(<|>); } |
313 | "#, | 342 | "#, |
314 | expect![[r#" | 343 | expect![[r#" |
315 | fn foo<T>() -> T | 344 | fn foo() -> {unknown} |
316 | where T: Copy + Display | ||
317 | () | 345 | () |
318 | "#]], | 346 | "#]], |
319 | ); | 347 | ); |
@@ -323,11 +351,14 @@ fn bar() { foo(<|>); } | |||
323 | fn test_fn_signature_for_impl() { | 351 | fn test_fn_signature_for_impl() { |
324 | check( | 352 | check( |
325 | r#" | 353 | r#" |
326 | struct F; impl F { pub fn new() { F{}} } | 354 | struct F; |
327 | fn bar() {let _ : F = F::new(<|>);} | 355 | impl F { pub fn new() { } } |
356 | fn bar() { | ||
357 | let _ : F = F::new(<|>); | ||
358 | } | ||
328 | "#, | 359 | "#, |
329 | expect![[r#" | 360 | expect![[r#" |
330 | pub fn new() | 361 | fn new() |
331 | () | 362 | () |
332 | "#]], | 363 | "#]], |
333 | ); | 364 | ); |
@@ -346,8 +377,8 @@ fn bar() { | |||
346 | } | 377 | } |
347 | "#, | 378 | "#, |
348 | expect![[r#" | 379 | expect![[r#" |
349 | pub fn do_it(&self) | 380 | fn do_it(&self) |
350 | (&self) | 381 | () |
351 | "#]], | 382 | "#]], |
352 | ); | 383 | ); |
353 | } | 384 | } |
@@ -357,16 +388,33 @@ fn bar() { | |||
357 | check( | 388 | check( |
358 | r#" | 389 | r#" |
359 | struct S; | 390 | struct S; |
360 | impl S { pub fn do_it(&self, x: i32) {} } | 391 | impl S { |
392 | fn foo(&self, x: i32) {} | ||
393 | } | ||
361 | 394 | ||
362 | fn bar() { | 395 | fn main() { S.foo(<|>); } |
363 | let s: S = S; | 396 | "#, |
364 | s.do_it(<|>); | 397 | expect![[r#" |
398 | fn foo(&self, x: i32) | ||
399 | (<x: i32>) | ||
400 | "#]], | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn test_fn_signature_for_method_with_arg_as_assoc_fn() { | ||
406 | check( | ||
407 | r#" | ||
408 | struct S; | ||
409 | impl S { | ||
410 | fn foo(&self, x: i32) {} | ||
365 | } | 411 | } |
412 | |||
413 | fn main() { S::foo(<|>); } | ||
366 | "#, | 414 | "#, |
367 | expect![[r#" | 415 | expect![[r#" |
368 | pub fn do_it(&self, x: i32) | 416 | fn foo(self: &S, x: i32) |
369 | (&self, <x: i32>) | 417 | (<self: &S>, x: i32) |
370 | "#]], | 418 | "#]], |
371 | ); | 419 | ); |
372 | } | 420 | } |
@@ -425,7 +473,7 @@ pub fn do() { | |||
425 | assert_eq!(6, my_crate::add_one(5)); | 473 | assert_eq!(6, my_crate::add_one(5)); |
426 | ``` | 474 | ``` |
427 | ------ | 475 | ------ |
428 | pub fn add_one(x: i32) -> i32 | 476 | fn add_one(x: i32) -> i32 |
429 | (<x: i32>) | 477 | (<x: i32>) |
430 | "##]], | 478 | "##]], |
431 | ); | 479 | ); |
@@ -467,7 +515,7 @@ pub fn do_it() { | |||
467 | assert_eq!(6, my_crate::add_one(5)); | 515 | assert_eq!(6, my_crate::add_one(5)); |
468 | ``` | 516 | ``` |
469 | ------ | 517 | ------ |
470 | pub fn add_one(x: i32) -> i32 | 518 | fn add_one(x: i32) -> i32 |
471 | (<x: i32>) | 519 | (<x: i32>) |
472 | "##]], | 520 | "##]], |
473 | ); | 521 | ); |
@@ -505,8 +553,8 @@ pub fn foo(mut r: WriteHandler<()>) { | |||
505 | 553 | ||
506 | By default this method stops actor's `Context`. | 554 | By default this method stops actor's `Context`. |
507 | ------ | 555 | ------ |
508 | fn finished(&mut self, ctx: &mut Self::Context) | 556 | fn finished(&mut self, ctx: &mut {unknown}) |
509 | (&mut self, <ctx: &mut Self::Context>) | 557 | (<ctx: &mut {unknown}>) |
510 | "#]], | 558 | "#]], |
511 | ); | 559 | ); |
512 | } | 560 | } |
@@ -539,7 +587,7 @@ fn main() { | |||
539 | "#, | 587 | "#, |
540 | expect![[r#" | 588 | expect![[r#" |
541 | fn bar(&self, _: u32) | 589 | fn bar(&self, _: u32) |
542 | (&self, <_: u32>) | 590 | (<_: u32>) |
543 | "#]], | 591 | "#]], |
544 | ); | 592 | ); |
545 | } | 593 | } |
@@ -549,15 +597,15 @@ fn main() { | |||
549 | check( | 597 | check( |
550 | r#" | 598 | r#" |
551 | /// A cool tuple struct | 599 | /// A cool tuple struct |
552 | struct TS(u32, i32); | 600 | struct S(u32, i32); |
553 | fn main() { | 601 | fn main() { |
554 | let s = TS(0, <|>); | 602 | let s = S(0, <|>); |
555 | } | 603 | } |
556 | "#, | 604 | "#, |
557 | expect![[r#" | 605 | expect![[r#" |
558 | A cool tuple struct | 606 | A cool tuple struct |
559 | ------ | 607 | ------ |
560 | struct TS(u32, i32) -> TS | 608 | struct S(u32, i32) |
561 | (u32, <i32>) | 609 | (u32, <i32>) |
562 | "#]], | 610 | "#]], |
563 | ); | 611 | ); |
@@ -567,32 +615,19 @@ fn main() { | |||
567 | fn generic_struct() { | 615 | fn generic_struct() { |
568 | check( | 616 | check( |
569 | r#" | 617 | r#" |
570 | struct TS<T>(T); | 618 | struct S<T>(T); |
571 | fn main() { | 619 | fn main() { |
572 | let s = TS(<|>); | 620 | let s = S(<|>); |
573 | } | 621 | } |
574 | "#, | 622 | "#, |
575 | expect![[r#" | 623 | expect![[r#" |
576 | struct TS<T>(T) -> TS | 624 | struct S({unknown}) |
577 | (<T>) | 625 | (<{unknown}>) |
578 | "#]], | 626 | "#]], |
579 | ); | 627 | ); |
580 | } | 628 | } |
581 | 629 | ||
582 | #[test] | 630 | #[test] |
583 | fn cant_call_named_structs() { | ||
584 | check( | ||
585 | r#" | ||
586 | struct TS { x: u32, y: i32 } | ||
587 | fn main() { | ||
588 | let s = TS(<|>); | ||
589 | } | ||
590 | "#, | ||
591 | expect![[""]], | ||
592 | ); | ||
593 | } | ||
594 | |||
595 | #[test] | ||
596 | fn works_for_enum_variants() { | 631 | fn works_for_enum_variants() { |
597 | check( | 632 | check( |
598 | r#" | 633 | r#" |
@@ -612,14 +647,27 @@ fn main() { | |||
612 | expect![[r#" | 647 | expect![[r#" |
613 | A Variant | 648 | A Variant |
614 | ------ | 649 | ------ |
615 | E::A(0: i32) | 650 | enum E::A(i32) |
616 | (<0: i32>) | 651 | (<i32>) |
617 | "#]], | 652 | "#]], |
618 | ); | 653 | ); |
619 | } | 654 | } |
620 | 655 | ||
621 | #[test] | 656 | #[test] |
622 | fn cant_call_enum_records() { | 657 | fn cant_call_struct_record() { |
658 | check( | ||
659 | r#" | ||
660 | struct S { x: u32, y: i32 } | ||
661 | fn main() { | ||
662 | let s = S(<|>); | ||
663 | } | ||
664 | "#, | ||
665 | expect![[""]], | ||
666 | ); | ||
667 | } | ||
668 | |||
669 | #[test] | ||
670 | fn cant_call_enum_record() { | ||
623 | check( | 671 | check( |
624 | r#" | 672 | r#" |
625 | enum E { | 673 | enum E { |
@@ -640,41 +688,51 @@ fn main() { | |||
640 | } | 688 | } |
641 | 689 | ||
642 | #[test] | 690 | #[test] |
643 | fn fn_signature_for_macro() { | 691 | fn fn_signature_for_call_in_macro() { |
644 | check( | 692 | check( |
645 | r#" | 693 | r#" |
646 | /// empty macro | 694 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } |
647 | macro_rules! foo { | 695 | fn foo() { } |
648 | () => {} | 696 | id! { |
649 | } | 697 | fn bar() { foo(<|>); } |
650 | |||
651 | fn f() { | ||
652 | foo!(<|>); | ||
653 | } | 698 | } |
654 | "#, | 699 | "#, |
655 | expect![[r#" | 700 | expect![[r#" |
656 | empty macro | 701 | fn foo() |
657 | ------ | ||
658 | foo!() | ||
659 | () | 702 | () |
660 | "#]], | 703 | "#]], |
661 | ); | 704 | ); |
662 | } | 705 | } |
663 | 706 | ||
664 | #[test] | 707 | #[test] |
665 | fn fn_signature_for_call_in_macro() { | 708 | fn call_info_for_lambdas() { |
666 | check( | 709 | check( |
667 | r#" | 710 | r#" |
668 | macro_rules! id { ($($tt:tt)*) => { $($tt)* } } | 711 | struct S; |
669 | fn foo() { } | 712 | fn foo(s: S) -> i32 { 92 } |
670 | id! { | 713 | fn main() { |
671 | fn bar() { foo(<|>); } | 714 | (|s| foo(s))(<|>) |
672 | } | 715 | } |
673 | "#, | 716 | "#, |
674 | expect![[r#" | 717 | expect![[r#" |
675 | fn foo() | 718 | (S) -> i32 |
676 | () | 719 | (<S>) |
677 | "#]], | 720 | "#]], |
678 | ); | 721 | ) |
722 | } | ||
723 | |||
724 | #[test] | ||
725 | fn call_info_for_fn_ptr() { | ||
726 | check( | ||
727 | r#" | ||
728 | fn main(f: fn(i32, f64) -> char) { | ||
729 | f(0, <|>) | ||
730 | } | ||
731 | "#, | ||
732 | expect![[r#" | ||
733 | (i32, f64) -> char | ||
734 | (i32, <f64>) | ||
735 | "#]], | ||
736 | ) | ||
679 | } | 737 | } |
680 | } | 738 | } |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index a610fd6d1..cf716540f 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -43,7 +43,7 @@ use crate::{ | |||
43 | completion::{ | 43 | completion::{ |
44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | 44 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, |
45 | }, | 45 | }, |
46 | display::FunctionSignature, | 46 | display::function_declaration, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -125,8 +125,6 @@ fn add_function_impl( | |||
125 | ctx: &CompletionContext, | 125 | ctx: &CompletionContext, |
126 | func: hir::Function, | 126 | func: hir::Function, |
127 | ) { | 127 | ) { |
128 | let signature = FunctionSignature::from_hir(ctx.db, func); | ||
129 | |||
130 | let fn_name = func.name(ctx.db).to_string(); | 128 | let fn_name = func.name(ctx.db).to_string(); |
131 | 129 | ||
132 | let label = if !func.params(ctx.db).is_empty() { | 130 | let label = if !func.params(ctx.db).is_empty() { |
@@ -146,13 +144,14 @@ fn add_function_impl( | |||
146 | }; | 144 | }; |
147 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 145 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); |
148 | 146 | ||
147 | let function_decl = function_declaration(&func.source(ctx.db).value); | ||
149 | match ctx.config.snippet_cap { | 148 | match ctx.config.snippet_cap { |
150 | Some(cap) => { | 149 | Some(cap) => { |
151 | let snippet = format!("{} {{\n $0\n}}", signature); | 150 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
152 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | 151 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) |
153 | } | 152 | } |
154 | None => { | 153 | None => { |
155 | let header = format!("{} {{", signature); | 154 | let header = format!("{} {{", function_decl); |
156 | builder.text_edit(TextEdit::replace(range, header)) | 155 | builder.text_edit(TextEdit::replace(range, header)) |
157 | } | 156 | } |
158 | } | 157 | } |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 64349dcb8..c7b74e635 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, | 11 | completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind, |
12 | CompletionKind, Completions, | 12 | CompletionKind, Completions, |
13 | }, | 13 | }, |
14 | display::{const_label, macro_label, type_label, FunctionSignature}, | 14 | display::{const_label, function_declaration, macro_label, type_label}, |
15 | CompletionScore, RootDatabase, | 15 | CompletionScore, RootDatabase, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -195,7 +195,6 @@ impl Completions { | |||
195 | 195 | ||
196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); | 196 | let name = local_name.unwrap_or_else(|| func.name(ctx.db).to_string()); |
197 | let ast_node = func.source(ctx.db).value; | 197 | let ast_node = func.source(ctx.db).value; |
198 | let function_signature = FunctionSignature::from(&ast_node); | ||
199 | 198 | ||
200 | let mut builder = | 199 | let mut builder = |
201 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) | 200 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) |
@@ -206,13 +205,14 @@ impl Completions { | |||
206 | }) | 205 | }) |
207 | .set_documentation(func.docs(ctx.db)) | 206 | .set_documentation(func.docs(ctx.db)) |
208 | .set_deprecated(is_deprecated(func, ctx.db)) | 207 | .set_deprecated(is_deprecated(func, ctx.db)) |
209 | .detail(function_signature.to_string()); | 208 | .detail(function_declaration(&ast_node)); |
210 | 209 | ||
211 | let params = function_signature | 210 | let params = ast_node |
212 | .parameter_names | 211 | .param_list() |
213 | .iter() | 212 | .into_iter() |
214 | .skip(if function_signature.has_self_param { 1 } else { 0 }) | 213 | .flat_map(|it| it.params()) |
215 | .map(|name| name.trim_start_matches('_').into()) | 214 | .flat_map(|it| it.pat()) |
215 | .map(|pat| pat.to_string().trim_start_matches('_').into()) | ||
216 | .collect(); | 216 | .collect(); |
217 | 217 | ||
218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); | 218 | builder = builder.add_call_parens(ctx, name, Params::Named(params)); |
@@ -329,15 +329,10 @@ pub(crate) fn compute_score( | |||
329 | ty: &Type, | 329 | ty: &Type, |
330 | name: &str, | 330 | name: &str, |
331 | ) -> Option<CompletionScore> { | 331 | ) -> Option<CompletionScore> { |
332 | // FIXME: this should not fall back to string equality. | ||
333 | let ty = &ty.display(ctx.db).to_string(); | ||
334 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { | 332 | let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { |
335 | mark::hit!(record_field_type_match); | 333 | mark::hit!(record_field_type_match); |
336 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; | 334 | let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; |
337 | ( | 335 | (struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db)) |
338 | struct_field.name(ctx.db).to_string(), | ||
339 | struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), | ||
340 | ) | ||
341 | } else if let Some(active_parameter) = &ctx.active_parameter { | 336 | } else if let Some(active_parameter) = &ctx.active_parameter { |
342 | mark::hit!(active_param_type_match); | 337 | mark::hit!(active_param_type_match); |
343 | (active_parameter.name.clone(), active_parameter.ty.clone()) | 338 | (active_parameter.name.clone(), active_parameter.ty.clone()) |
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs index 70d2a2dd1..6d4151dd8 100644 --- a/crates/ra_ide/src/display.rs +++ b/crates/ra_ide/src/display.rs | |||
@@ -1,9 +1,7 @@ | |||
1 | //! This module contains utilities for turning SyntaxNodes and HIR types | 1 | //! This module contains utilities for turning SyntaxNodes and HIR types |
2 | //! into types that may be used to render in a UI. | 2 | //! into types that may be used to render in a UI. |
3 | 3 | ||
4 | mod function_signature; | ||
5 | mod navigation_target; | 4 | mod navigation_target; |
6 | mod structure; | ||
7 | mod short_label; | 5 | mod short_label; |
8 | 6 | ||
9 | use ra_syntax::{ | 7 | use ra_syntax::{ |
@@ -11,15 +9,49 @@ use ra_syntax::{ | |||
11 | SyntaxKind::{ATTR, COMMENT}, | 9 | SyntaxKind::{ATTR, COMMENT}, |
12 | }; | 10 | }; |
13 | 11 | ||
14 | pub use function_signature::FunctionSignature; | 12 | use ast::VisibilityOwner; |
15 | pub use navigation_target::NavigationTarget; | 13 | use stdx::format_to; |
16 | pub use structure::{file_structure, StructureNode}; | ||
17 | 14 | ||
15 | pub use navigation_target::NavigationTarget; | ||
18 | pub(crate) use navigation_target::{ToNav, TryToNav}; | 16 | pub(crate) use navigation_target::{ToNav, TryToNav}; |
19 | pub(crate) use short_label::ShortLabel; | 17 | pub(crate) use short_label::ShortLabel; |
20 | 18 | ||
21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 19 | pub(crate) fn function_declaration(node: &ast::FnDef) -> String { |
22 | FunctionSignature::from(node).to_string() | 20 | let mut buf = String::new(); |
21 | if let Some(vis) = node.visibility() { | ||
22 | format_to!(buf, "{} ", vis); | ||
23 | } | ||
24 | if node.async_token().is_some() { | ||
25 | format_to!(buf, "async "); | ||
26 | } | ||
27 | if node.const_token().is_some() { | ||
28 | format_to!(buf, "const "); | ||
29 | } | ||
30 | if node.unsafe_token().is_some() { | ||
31 | format_to!(buf, "unsafe "); | ||
32 | } | ||
33 | if let Some(abi) = node.abi() { | ||
34 | // Keyword `extern` is included in the string. | ||
35 | format_to!(buf, "{} ", abi); | ||
36 | } | ||
37 | if let Some(name) = node.name() { | ||
38 | format_to!(buf, "fn {}", name) | ||
39 | } | ||
40 | if let Some(type_params) = node.type_param_list() { | ||
41 | format_to!(buf, "{}", type_params); | ||
42 | } | ||
43 | if let Some(param_list) = node.param_list() { | ||
44 | format_to!(buf, "{}", param_list); | ||
45 | } | ||
46 | if let Some(ret_type) = node.ret_type() { | ||
47 | if ret_type.type_ref().is_some() { | ||
48 | format_to!(buf, " {}", ret_type); | ||
49 | } | ||
50 | } | ||
51 | if let Some(where_clause) = node.where_clause() { | ||
52 | format_to!(buf, "\n{}", where_clause); | ||
53 | } | ||
54 | buf | ||
23 | } | 55 | } |
24 | 56 | ||
25 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { | 57 | pub(crate) fn const_label(node: &ast::ConstDef) -> String { |
@@ -44,23 +76,6 @@ pub(crate) fn type_label(node: &ast::TypeAliasDef) -> String { | |||
44 | label.trim().to_owned() | 76 | label.trim().to_owned() |
45 | } | 77 | } |
46 | 78 | ||
47 | pub(crate) fn generic_parameters<N: TypeParamsOwner>(node: &N) -> Vec<String> { | ||
48 | let mut res = vec![]; | ||
49 | if let Some(type_params) = node.type_param_list() { | ||
50 | res.extend(type_params.lifetime_params().map(|p| p.syntax().text().to_string())); | ||
51 | res.extend(type_params.type_params().map(|p| p.syntax().text().to_string())); | ||
52 | } | ||
53 | res | ||
54 | } | ||
55 | |||
56 | pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> { | ||
57 | let mut res = vec![]; | ||
58 | if let Some(clause) = node.where_clause() { | ||
59 | res.extend(clause.predicates().map(|p| p.syntax().text().to_string())); | ||
60 | } | ||
61 | res | ||
62 | } | ||
63 | |||
64 | pub(crate) fn macro_label(node: &ast::MacroCall) -> String { | 79 | pub(crate) fn macro_label(node: &ast::MacroCall) -> String { |
65 | let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); | 80 | let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); |
66 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; | 81 | let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; |
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs deleted file mode 100644 index 1d39544d3..000000000 --- a/crates/ra_ide/src/display/function_signature.rs +++ /dev/null | |||
@@ -1,321 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | // FIXME: this modules relies on strings and AST way too much, and it should be | ||
4 | // rewritten (matklad 2020-05-07) | ||
5 | use std::{ | ||
6 | convert::From, | ||
7 | fmt::{self, Display}, | ||
8 | }; | ||
9 | |||
10 | use hir::{Docs, Documentation, HasSource, HirDisplay}; | ||
11 | use ra_ide_db::RootDatabase; | ||
12 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
13 | use stdx::{split_delim, SepBy}; | ||
14 | |||
15 | use crate::display::{generic_parameters, where_predicates}; | ||
16 | |||
17 | #[derive(Debug)] | ||
18 | pub enum CallableKind { | ||
19 | Function, | ||
20 | StructConstructor, | ||
21 | VariantConstructor, | ||
22 | Macro, | ||
23 | } | ||
24 | |||
25 | /// Contains information about a function signature | ||
26 | #[derive(Debug)] | ||
27 | pub struct FunctionSignature { | ||
28 | pub kind: CallableKind, | ||
29 | /// Optional visibility | ||
30 | pub visibility: Option<String>, | ||
31 | /// Qualifiers like `async`, `unsafe`, ... | ||
32 | pub qualifier: FunctionQualifier, | ||
33 | /// Name of the function | ||
34 | pub name: Option<String>, | ||
35 | /// Documentation for the function | ||
36 | pub doc: Option<Documentation>, | ||
37 | /// Generic parameters | ||
38 | pub generic_parameters: Vec<String>, | ||
39 | /// Parameters of the function | ||
40 | pub parameters: Vec<String>, | ||
41 | /// Parameter names of the function | ||
42 | pub parameter_names: Vec<String>, | ||
43 | /// Parameter types of the function | ||
44 | pub parameter_types: Vec<String>, | ||
45 | /// Optional return type | ||
46 | pub ret_type: Option<String>, | ||
47 | /// Where predicates | ||
48 | pub where_predicates: Vec<String>, | ||
49 | /// Self param presence | ||
50 | pub has_self_param: bool, | ||
51 | } | ||
52 | |||
53 | #[derive(Debug, Default)] | ||
54 | pub struct FunctionQualifier { | ||
55 | // `async` and `const` are mutually exclusive. Do we need to enforcing it here? | ||
56 | pub is_async: bool, | ||
57 | pub is_const: bool, | ||
58 | pub is_unsafe: bool, | ||
59 | /// The string `extern ".."` | ||
60 | pub extern_abi: Option<String>, | ||
61 | } | ||
62 | |||
63 | impl FunctionSignature { | ||
64 | pub(crate) fn from_hir(db: &RootDatabase, function: hir::Function) -> Self { | ||
65 | let ast_node = function.source(db).value; | ||
66 | let mut res = FunctionSignature::from(&ast_node); | ||
67 | res.doc = function.docs(db); | ||
68 | res | ||
69 | } | ||
70 | |||
71 | pub(crate) fn from_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> { | ||
72 | let node: ast::StructDef = st.source(db).value; | ||
73 | if let ast::StructKind::Record(_) = node.kind() { | ||
74 | return None; | ||
75 | }; | ||
76 | |||
77 | let mut params = vec![]; | ||
78 | let mut parameter_types = vec![]; | ||
79 | for field in st.fields(db).into_iter() { | ||
80 | let ty = field.signature_ty(db); | ||
81 | let raw_param = format!("{}", ty.display(db)); | ||
82 | |||
83 | if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) { | ||
84 | parameter_types.push(param_type.to_string()); | ||
85 | } else { | ||
86 | // useful when you have tuple struct | ||
87 | parameter_types.push(raw_param.clone()); | ||
88 | } | ||
89 | params.push(raw_param); | ||
90 | } | ||
91 | |||
92 | Some(FunctionSignature { | ||
93 | kind: CallableKind::StructConstructor, | ||
94 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | ||
95 | // Do we need `const`? | ||
96 | qualifier: Default::default(), | ||
97 | name: node.name().map(|n| n.text().to_string()), | ||
98 | ret_type: node.name().map(|n| n.text().to_string()), | ||
99 | parameters: params, | ||
100 | parameter_names: vec![], | ||
101 | parameter_types, | ||
102 | generic_parameters: generic_parameters(&node), | ||
103 | where_predicates: where_predicates(&node), | ||
104 | doc: st.docs(db), | ||
105 | has_self_param: false, | ||
106 | }) | ||
107 | } | ||
108 | |||
109 | pub(crate) fn from_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> { | ||
110 | let node: ast::EnumVariant = variant.source(db).value; | ||
111 | match node.kind() { | ||
112 | ast::StructKind::Record(_) | ast::StructKind::Unit => return None, | ||
113 | _ => (), | ||
114 | }; | ||
115 | |||
116 | let parent_name = variant.parent_enum(db).name(db).to_string(); | ||
117 | |||
118 | let name = format!("{}::{}", parent_name, variant.name(db)); | ||
119 | |||
120 | let mut params = vec![]; | ||
121 | let mut parameter_types = vec![]; | ||
122 | for field in variant.fields(db).into_iter() { | ||
123 | let ty = field.signature_ty(db); | ||
124 | let raw_param = format!("{}", ty.display(db)); | ||
125 | if let Some(param_type) = raw_param.split(':').nth(1).and_then(|it| it.get(1..)) { | ||
126 | parameter_types.push(param_type.to_string()); | ||
127 | } else { | ||
128 | // The unwrap_or_else is useful when you have tuple | ||
129 | parameter_types.push(raw_param); | ||
130 | } | ||
131 | let name = field.name(db); | ||
132 | |||
133 | params.push(format!("{}: {}", name, ty.display(db))); | ||
134 | } | ||
135 | |||
136 | Some(FunctionSignature { | ||
137 | kind: CallableKind::VariantConstructor, | ||
138 | visibility: None, | ||
139 | // Do we need `const`? | ||
140 | qualifier: Default::default(), | ||
141 | name: Some(name), | ||
142 | ret_type: None, | ||
143 | parameters: params, | ||
144 | parameter_names: vec![], | ||
145 | parameter_types, | ||
146 | generic_parameters: vec![], | ||
147 | where_predicates: vec![], | ||
148 | doc: variant.docs(db), | ||
149 | has_self_param: false, | ||
150 | }) | ||
151 | } | ||
152 | |||
153 | pub(crate) fn from_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> { | ||
154 | let node: ast::MacroCall = macro_def.source(db).value; | ||
155 | |||
156 | let params = vec![]; | ||
157 | |||
158 | Some(FunctionSignature { | ||
159 | kind: CallableKind::Macro, | ||
160 | visibility: None, | ||
161 | qualifier: Default::default(), | ||
162 | name: node.name().map(|n| n.text().to_string()), | ||
163 | ret_type: None, | ||
164 | parameters: params, | ||
165 | parameter_names: vec![], | ||
166 | parameter_types: vec![], | ||
167 | generic_parameters: vec![], | ||
168 | where_predicates: vec![], | ||
169 | doc: macro_def.docs(db), | ||
170 | has_self_param: false, | ||
171 | }) | ||
172 | } | ||
173 | } | ||
174 | |||
175 | impl From<&'_ ast::FnDef> for FunctionSignature { | ||
176 | fn from(node: &ast::FnDef) -> FunctionSignature { | ||
177 | fn param_list(node: &ast::FnDef) -> (bool, Vec<String>, Vec<String>) { | ||
178 | let mut res = vec![]; | ||
179 | let mut res_types = vec![]; | ||
180 | let mut has_self_param = false; | ||
181 | if let Some(param_list) = node.param_list() { | ||
182 | if let Some(self_param) = param_list.self_param() { | ||
183 | has_self_param = true; | ||
184 | let raw_param = self_param.syntax().text().to_string(); | ||
185 | |||
186 | res_types.push( | ||
187 | raw_param | ||
188 | .split(':') | ||
189 | .nth(1) | ||
190 | .and_then(|it| it.get(1..)) | ||
191 | .unwrap_or_else(|| "Self") | ||
192 | .to_string(), | ||
193 | ); | ||
194 | res.push(raw_param); | ||
195 | } | ||
196 | |||
197 | // macro-generated functions are missing whitespace | ||
198 | fn fmt_param(param: ast::Param) -> String { | ||
199 | let text = param.syntax().text().to_string(); | ||
200 | match split_delim(&text, ':') { | ||
201 | Some((left, right)) => format!("{}: {}", left.trim(), right.trim()), | ||
202 | _ => text, | ||
203 | } | ||
204 | } | ||
205 | |||
206 | res.extend(param_list.params().map(fmt_param)); | ||
207 | res_types.extend(param_list.params().map(|param| { | ||
208 | let param_text = param.syntax().text().to_string(); | ||
209 | match param_text.split(':').nth(1).and_then(|it| it.get(1..)) { | ||
210 | Some(it) => it.to_string(), | ||
211 | None => param_text, | ||
212 | } | ||
213 | })); | ||
214 | } | ||
215 | (has_self_param, res, res_types) | ||
216 | } | ||
217 | |||
218 | fn param_name_list(node: &ast::FnDef) -> Vec<String> { | ||
219 | let mut res = vec![]; | ||
220 | if let Some(param_list) = node.param_list() { | ||
221 | if let Some(self_param) = param_list.self_param() { | ||
222 | res.push(self_param.syntax().text().to_string()) | ||
223 | } | ||
224 | |||
225 | res.extend( | ||
226 | param_list | ||
227 | .params() | ||
228 | .map(|param| { | ||
229 | Some( | ||
230 | param | ||
231 | .pat()? | ||
232 | .syntax() | ||
233 | .descendants() | ||
234 | .find_map(ast::Name::cast)? | ||
235 | .text() | ||
236 | .to_string(), | ||
237 | ) | ||
238 | }) | ||
239 | .map(|param| param.unwrap_or_default()), | ||
240 | ); | ||
241 | } | ||
242 | res | ||
243 | } | ||
244 | |||
245 | let (has_self_param, parameters, parameter_types) = param_list(node); | ||
246 | |||
247 | FunctionSignature { | ||
248 | kind: CallableKind::Function, | ||
249 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | ||
250 | qualifier: FunctionQualifier { | ||
251 | is_async: node.async_token().is_some(), | ||
252 | is_const: node.const_token().is_some(), | ||
253 | is_unsafe: node.unsafe_token().is_some(), | ||
254 | extern_abi: node.abi().map(|n| n.to_string()), | ||
255 | }, | ||
256 | name: node.name().map(|n| n.text().to_string()), | ||
257 | ret_type: node | ||
258 | .ret_type() | ||
259 | .and_then(|r| r.type_ref()) | ||
260 | .map(|n| n.syntax().text().to_string()), | ||
261 | parameters, | ||
262 | parameter_names: param_name_list(node), | ||
263 | parameter_types, | ||
264 | generic_parameters: generic_parameters(node), | ||
265 | where_predicates: where_predicates(node), | ||
266 | // docs are processed separately | ||
267 | doc: None, | ||
268 | has_self_param, | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | |||
273 | impl Display for FunctionSignature { | ||
274 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
275 | if let Some(t) = &self.visibility { | ||
276 | write!(f, "{} ", t)?; | ||
277 | } | ||
278 | |||
279 | if self.qualifier.is_async { | ||
280 | write!(f, "async ")?; | ||
281 | } | ||
282 | |||
283 | if self.qualifier.is_const { | ||
284 | write!(f, "const ")?; | ||
285 | } | ||
286 | |||
287 | if self.qualifier.is_unsafe { | ||
288 | write!(f, "unsafe ")?; | ||
289 | } | ||
290 | |||
291 | if let Some(extern_abi) = &self.qualifier.extern_abi { | ||
292 | // Keyword `extern` is included in the string. | ||
293 | write!(f, "{} ", extern_abi)?; | ||
294 | } | ||
295 | |||
296 | if let Some(name) = &self.name { | ||
297 | match self.kind { | ||
298 | CallableKind::Function => write!(f, "fn {}", name)?, | ||
299 | CallableKind::StructConstructor => write!(f, "struct {}", name)?, | ||
300 | CallableKind::VariantConstructor => write!(f, "{}", name)?, | ||
301 | CallableKind::Macro => write!(f, "{}!", name)?, | ||
302 | } | ||
303 | } | ||
304 | |||
305 | if !self.generic_parameters.is_empty() { | ||
306 | write!(f, "{}", self.generic_parameters.iter().sep_by(", ").surround_with("<", ">"))?; | ||
307 | } | ||
308 | |||
309 | write!(f, "{}", self.parameters.iter().sep_by(", ").surround_with("(", ")"))?; | ||
310 | |||
311 | if let Some(t) = &self.ret_type { | ||
312 | write!(f, " -> {}", t)?; | ||
313 | } | ||
314 | |||
315 | if !self.where_predicates.is_empty() { | ||
316 | write!(f, "\nwhere {}", self.where_predicates.iter().sep_by(",\n "))?; | ||
317 | } | ||
318 | |||
319 | Ok(()) | ||
320 | } | ||
321 | } | ||
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs index 8bf2428ed..6dcb9415a 100644 --- a/crates/ra_ide/src/display/navigation_target.rs +++ b/crates/ra_ide/src/display/navigation_target.rs | |||
@@ -22,15 +22,28 @@ use super::short_label::ShortLabel; | |||
22 | /// code, like a function or a struct, but this is not strictly required. | 22 | /// code, like a function or a struct, but this is not strictly required. |
23 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 23 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
24 | pub struct NavigationTarget { | 24 | pub struct NavigationTarget { |
25 | // FIXME: use FileRange? | 25 | pub file_id: FileId, |
26 | file_id: FileId, | 26 | /// Range which encompasses the whole element. |
27 | full_range: TextRange, | 27 | /// |
28 | name: SmolStr, | 28 | /// Should include body, doc comments, attributes, etc. |
29 | kind: SyntaxKind, | 29 | /// |
30 | focus_range: Option<TextRange>, | 30 | /// Clients should use this range to answer "is the cursor inside the |
31 | container_name: Option<SmolStr>, | 31 | /// element?" question. |
32 | description: Option<String>, | 32 | pub full_range: TextRange, |
33 | docs: Option<String>, | 33 | /// A "most interesting" range withing the `full_range`. |
34 | /// | ||
35 | /// Typically, `full_range` is the whole syntax node, including doc | ||
36 | /// comments, and `focus_range` is the range of the identifier. "Most | ||
37 | /// interesting" range within the full range, typically the range of | ||
38 | /// identifier. | ||
39 | /// | ||
40 | /// Clients should place the cursor on this range when navigating to this target. | ||
41 | pub focus_range: Option<TextRange>, | ||
42 | pub name: SmolStr, | ||
43 | pub kind: SyntaxKind, | ||
44 | pub container_name: Option<SmolStr>, | ||
45 | pub description: Option<String>, | ||
46 | pub docs: Option<String>, | ||
34 | } | 47 | } |
35 | 48 | ||
36 | pub(crate) trait ToNav { | 49 | pub(crate) trait ToNav { |
@@ -42,44 +55,9 @@ pub(crate) trait TryToNav { | |||
42 | } | 55 | } |
43 | 56 | ||
44 | impl NavigationTarget { | 57 | impl NavigationTarget { |
45 | /// When `focus_range` is specified, returns it. otherwise | 58 | pub fn focus_or_full_range(&self) -> TextRange { |
46 | /// returns `full_range` | ||
47 | pub fn range(&self) -> TextRange { | ||
48 | self.focus_range.unwrap_or(self.full_range) | 59 | self.focus_range.unwrap_or(self.full_range) |
49 | } | 60 | } |
50 | /// A "most interesting" range withing the `full_range`. | ||
51 | /// | ||
52 | /// Typically, `full_range` is the whole syntax node, | ||
53 | /// including doc comments, and `focus_range` is the range of the identifier. | ||
54 | pub fn focus_range(&self) -> Option<TextRange> { | ||
55 | self.focus_range | ||
56 | } | ||
57 | pub fn full_range(&self) -> TextRange { | ||
58 | self.full_range | ||
59 | } | ||
60 | pub fn file_id(&self) -> FileId { | ||
61 | self.file_id | ||
62 | } | ||
63 | |||
64 | pub fn name(&self) -> &SmolStr { | ||
65 | &self.name | ||
66 | } | ||
67 | |||
68 | pub fn container_name(&self) -> Option<&SmolStr> { | ||
69 | self.container_name.as_ref() | ||
70 | } | ||
71 | |||
72 | pub fn kind(&self) -> SyntaxKind { | ||
73 | self.kind | ||
74 | } | ||
75 | |||
76 | pub fn docs(&self) -> Option<&str> { | ||
77 | self.docs.as_deref() | ||
78 | } | ||
79 | |||
80 | pub fn description(&self) -> Option<&str> { | ||
81 | self.description.as_deref() | ||
82 | } | ||
83 | 61 | ||
84 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 62 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
85 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 63 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
@@ -107,17 +85,12 @@ impl NavigationTarget { | |||
107 | 85 | ||
108 | #[cfg(test)] | 86 | #[cfg(test)] |
109 | pub(crate) fn debug_render(&self) -> String { | 87 | pub(crate) fn debug_render(&self) -> String { |
110 | let mut buf = format!( | 88 | let mut buf = |
111 | "{} {:?} {:?} {:?}", | 89 | format!("{} {:?} {:?} {:?}", self.name, self.kind, self.file_id, self.full_range); |
112 | self.name(), | 90 | if let Some(focus_range) = self.focus_range { |
113 | self.kind(), | ||
114 | self.file_id(), | ||
115 | self.full_range() | ||
116 | ); | ||
117 | if let Some(focus_range) = self.focus_range() { | ||
118 | buf.push_str(&format!(" {:?}", focus_range)) | 91 | buf.push_str(&format!(" {:?}", focus_range)) |
119 | } | 92 | } |
120 | if let Some(container_name) = self.container_name() { | 93 | if let Some(container_name) = &self.container_name { |
121 | buf.push_str(&format!(" {}", container_name)) | 94 | buf.push_str(&format!(" {}", container_name)) |
122 | } | 95 | } |
123 | buf | 96 | buf |
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs index d37260e96..5588130a1 100644 --- a/crates/ra_ide/src/display/short_label.rs +++ b/crates/ra_ide/src/display/short_label.rs | |||
@@ -9,7 +9,7 @@ pub(crate) trait ShortLabel { | |||
9 | 9 | ||
10 | impl ShortLabel for ast::FnDef { | 10 | impl ShortLabel for ast::FnDef { |
11 | fn short_label(&self) -> Option<String> { | 11 | fn short_label(&self) -> Option<String> { |
12 | Some(crate::display::function_label(self)) | 12 | Some(crate::display::function_declaration(self)) |
13 | } | 13 | } |
14 | } | 14 | } |
15 | 15 | ||
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/file_structure.rs index 1f6a3febf..1f6a3febf 100644 --- a/crates/ra_ide/src/display/structure.rs +++ b/crates/ra_ide/src/file_structure.rs | |||
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index c30b20611..db6d20a37 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -130,7 +130,7 @@ mod tests { | |||
130 | assert_eq!(navs.len(), 1); | 130 | assert_eq!(navs.len(), 1); |
131 | 131 | ||
132 | let nav = navs.pop().unwrap(); | 132 | let nav = navs.pop().unwrap(); |
133 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); | 133 | assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); |
134 | } | 134 | } |
135 | 135 | ||
136 | #[test] | 136 | #[test] |
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs index 9acc960fc..3ee048f28 100644 --- a/crates/ra_ide/src/goto_implementation.rs +++ b/crates/ra_ide/src/goto_implementation.rs | |||
@@ -98,7 +98,7 @@ mod tests { | |||
98 | 98 | ||
99 | let mut actual = navs | 99 | let mut actual = navs |
100 | .into_iter() | 100 | .into_iter() |
101 | .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() }) | 101 | .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) |
102 | .collect::<Vec<_>>(); | 102 | .collect::<Vec<_>>(); |
103 | actual.sort_by_key(key); | 103 | actual.sort_by_key(key); |
104 | 104 | ||
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs index 069cb283e..8f52feea6 100644 --- a/crates/ra_ide/src/goto_type_definition.rs +++ b/crates/ra_ide/src/goto_type_definition.rs | |||
@@ -67,7 +67,7 @@ mod tests { | |||
67 | let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info; | 67 | let mut navs = analysis.goto_type_definition(position).unwrap().unwrap().info; |
68 | assert_eq!(navs.len(), 1); | 68 | assert_eq!(navs.len(), 1); |
69 | let nav = navs.pop().unwrap(); | 69 | let nav = navs.pop().unwrap(); |
70 | assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() }); | 70 | assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); |
71 | } | 71 | } |
72 | 72 | ||
73 | #[test] | 73 | #[test] |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index a4c97e7f9..d067c339d 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -133,8 +133,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
133 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 133 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
134 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | 134 | fn to_action(nav_target: NavigationTarget) -> HoverAction { |
135 | HoverAction::Implementaion(FilePosition { | 135 | HoverAction::Implementaion(FilePosition { |
136 | file_id: nav_target.file_id(), | 136 | file_id: nav_target.file_id, |
137 | offset: nav_target.range().start(), | 137 | offset: nav_target.focus_or_full_range().start(), |
138 | }) | 138 | }) |
139 | } | 139 | } |
140 | 140 | ||
@@ -1357,11 +1357,11 @@ fn foo_<|>test() {} | |||
1357 | 1, | 1357 | 1, |
1358 | ), | 1358 | ), |
1359 | full_range: 0..24, | 1359 | full_range: 0..24, |
1360 | name: "foo_test", | ||
1361 | kind: FN_DEF, | ||
1362 | focus_range: Some( | 1360 | focus_range: Some( |
1363 | 11..19, | 1361 | 11..19, |
1364 | ), | 1362 | ), |
1363 | name: "foo_test", | ||
1364 | kind: FN_DEF, | ||
1365 | container_name: None, | 1365 | container_name: None, |
1366 | description: None, | 1366 | description: None, |
1367 | docs: None, | 1367 | docs: None, |
@@ -1400,11 +1400,11 @@ mod tests<|> { | |||
1400 | 1, | 1400 | 1, |
1401 | ), | 1401 | ), |
1402 | full_range: 0..46, | 1402 | full_range: 0..46, |
1403 | name: "tests", | ||
1404 | kind: MODULE, | ||
1405 | focus_range: Some( | 1403 | focus_range: Some( |
1406 | 4..9, | 1404 | 4..9, |
1407 | ), | 1405 | ), |
1406 | name: "tests", | ||
1407 | kind: MODULE, | ||
1408 | container_name: None, | 1408 | container_name: None, |
1409 | description: None, | 1409 | description: None, |
1410 | docs: None, | 1410 | docs: None, |
@@ -1439,11 +1439,11 @@ fn main() { let s<|>t = S{ f1:0 }; } | |||
1439 | 1, | 1439 | 1, |
1440 | ), | 1440 | ), |
1441 | full_range: 0..19, | 1441 | full_range: 0..19, |
1442 | name: "S", | ||
1443 | kind: STRUCT_DEF, | ||
1444 | focus_range: Some( | 1442 | focus_range: Some( |
1445 | 7..8, | 1443 | 7..8, |
1446 | ), | 1444 | ), |
1445 | name: "S", | ||
1446 | kind: STRUCT_DEF, | ||
1447 | container_name: None, | 1447 | container_name: None, |
1448 | description: Some( | 1448 | description: Some( |
1449 | "struct S", | 1449 | "struct S", |
@@ -1478,11 +1478,11 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } | |||
1478 | 1, | 1478 | 1, |
1479 | ), | 1479 | ), |
1480 | full_range: 17..37, | 1480 | full_range: 17..37, |
1481 | name: "S", | ||
1482 | kind: STRUCT_DEF, | ||
1483 | focus_range: Some( | 1481 | focus_range: Some( |
1484 | 24..25, | 1482 | 24..25, |
1485 | ), | 1483 | ), |
1484 | name: "S", | ||
1485 | kind: STRUCT_DEF, | ||
1486 | container_name: None, | 1486 | container_name: None, |
1487 | description: Some( | 1487 | description: Some( |
1488 | "struct S", | 1488 | "struct S", |
@@ -1497,11 +1497,11 @@ fn main() { let s<|>t = S{ f1:Arg(0) }; } | |||
1497 | 1, | 1497 | 1, |
1498 | ), | 1498 | ), |
1499 | full_range: 0..16, | 1499 | full_range: 0..16, |
1500 | name: "Arg", | ||
1501 | kind: STRUCT_DEF, | ||
1502 | focus_range: Some( | 1500 | focus_range: Some( |
1503 | 7..10, | 1501 | 7..10, |
1504 | ), | 1502 | ), |
1503 | name: "Arg", | ||
1504 | kind: STRUCT_DEF, | ||
1505 | container_name: None, | 1505 | container_name: None, |
1506 | description: Some( | 1506 | description: Some( |
1507 | "struct Arg", | 1507 | "struct Arg", |
@@ -1536,11 +1536,11 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } | |||
1536 | 1, | 1536 | 1, |
1537 | ), | 1537 | ), |
1538 | full_range: 17..37, | 1538 | full_range: 17..37, |
1539 | name: "S", | ||
1540 | kind: STRUCT_DEF, | ||
1541 | focus_range: Some( | 1539 | focus_range: Some( |
1542 | 24..25, | 1540 | 24..25, |
1543 | ), | 1541 | ), |
1542 | name: "S", | ||
1543 | kind: STRUCT_DEF, | ||
1544 | container_name: None, | 1544 | container_name: None, |
1545 | description: Some( | 1545 | description: Some( |
1546 | "struct S", | 1546 | "struct S", |
@@ -1555,11 +1555,11 @@ fn main() { let s<|>t = S{ f1: S{ f1: Arg(0) } }; } | |||
1555 | 1, | 1555 | 1, |
1556 | ), | 1556 | ), |
1557 | full_range: 0..16, | 1557 | full_range: 0..16, |
1558 | name: "Arg", | ||
1559 | kind: STRUCT_DEF, | ||
1560 | focus_range: Some( | 1558 | focus_range: Some( |
1561 | 7..10, | 1559 | 7..10, |
1562 | ), | 1560 | ), |
1561 | name: "Arg", | ||
1562 | kind: STRUCT_DEF, | ||
1563 | container_name: None, | 1563 | container_name: None, |
1564 | description: Some( | 1564 | description: Some( |
1565 | "struct Arg", | 1565 | "struct Arg", |
@@ -1597,11 +1597,11 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
1597 | 1, | 1597 | 1, |
1598 | ), | 1598 | ), |
1599 | full_range: 0..14, | 1599 | full_range: 0..14, |
1600 | name: "A", | ||
1601 | kind: STRUCT_DEF, | ||
1602 | focus_range: Some( | 1600 | focus_range: Some( |
1603 | 7..8, | 1601 | 7..8, |
1604 | ), | 1602 | ), |
1603 | name: "A", | ||
1604 | kind: STRUCT_DEF, | ||
1605 | container_name: None, | 1605 | container_name: None, |
1606 | description: Some( | 1606 | description: Some( |
1607 | "struct A", | 1607 | "struct A", |
@@ -1616,11 +1616,11 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
1616 | 1, | 1616 | 1, |
1617 | ), | 1617 | ), |
1618 | full_range: 15..29, | 1618 | full_range: 15..29, |
1619 | name: "B", | ||
1620 | kind: STRUCT_DEF, | ||
1621 | focus_range: Some( | 1619 | focus_range: Some( |
1622 | 22..23, | 1620 | 22..23, |
1623 | ), | 1621 | ), |
1622 | name: "B", | ||
1623 | kind: STRUCT_DEF, | ||
1624 | container_name: None, | 1624 | container_name: None, |
1625 | description: Some( | 1625 | description: Some( |
1626 | "struct B", | 1626 | "struct B", |
@@ -1635,11 +1635,11 @@ fn main() { let s<|>t = (A(1), B(2), M::C(3) ); } | |||
1635 | 1, | 1635 | 1, |
1636 | ), | 1636 | ), |
1637 | full_range: 42..60, | 1637 | full_range: 42..60, |
1638 | name: "C", | ||
1639 | kind: STRUCT_DEF, | ||
1640 | focus_range: Some( | 1638 | focus_range: Some( |
1641 | 53..54, | 1639 | 53..54, |
1642 | ), | 1640 | ), |
1641 | name: "C", | ||
1642 | kind: STRUCT_DEF, | ||
1643 | container_name: None, | 1643 | container_name: None, |
1644 | description: Some( | 1644 | description: Some( |
1645 | "pub struct C", | 1645 | "pub struct C", |
@@ -1674,11 +1674,11 @@ fn main() { let s<|>t = foo(); } | |||
1674 | 1, | 1674 | 1, |
1675 | ), | 1675 | ), |
1676 | full_range: 0..12, | 1676 | full_range: 0..12, |
1677 | name: "Foo", | ||
1678 | kind: TRAIT_DEF, | ||
1679 | focus_range: Some( | 1677 | focus_range: Some( |
1680 | 6..9, | 1678 | 6..9, |
1681 | ), | 1679 | ), |
1680 | name: "Foo", | ||
1681 | kind: TRAIT_DEF, | ||
1682 | container_name: None, | 1682 | container_name: None, |
1683 | description: Some( | 1683 | description: Some( |
1684 | "trait Foo", | 1684 | "trait Foo", |
@@ -1714,11 +1714,11 @@ fn main() { let s<|>t = foo(); } | |||
1714 | 1, | 1714 | 1, |
1715 | ), | 1715 | ), |
1716 | full_range: 0..15, | 1716 | full_range: 0..15, |
1717 | name: "Foo", | ||
1718 | kind: TRAIT_DEF, | ||
1719 | focus_range: Some( | 1717 | focus_range: Some( |
1720 | 6..9, | 1718 | 6..9, |
1721 | ), | 1719 | ), |
1720 | name: "Foo", | ||
1721 | kind: TRAIT_DEF, | ||
1722 | container_name: None, | 1722 | container_name: None, |
1723 | description: Some( | 1723 | description: Some( |
1724 | "trait Foo", | 1724 | "trait Foo", |
@@ -1733,11 +1733,11 @@ fn main() { let s<|>t = foo(); } | |||
1733 | 1, | 1733 | 1, |
1734 | ), | 1734 | ), |
1735 | full_range: 16..25, | 1735 | full_range: 16..25, |
1736 | name: "S", | ||
1737 | kind: STRUCT_DEF, | ||
1738 | focus_range: Some( | 1736 | focus_range: Some( |
1739 | 23..24, | 1737 | 23..24, |
1740 | ), | 1738 | ), |
1739 | name: "S", | ||
1740 | kind: STRUCT_DEF, | ||
1741 | container_name: None, | 1741 | container_name: None, |
1742 | description: Some( | 1742 | description: Some( |
1743 | "struct S", | 1743 | "struct S", |
@@ -1773,11 +1773,11 @@ fn main() { let s<|>t = foo(); } | |||
1773 | 1, | 1773 | 1, |
1774 | ), | 1774 | ), |
1775 | full_range: 0..12, | 1775 | full_range: 0..12, |
1776 | name: "Foo", | ||
1777 | kind: TRAIT_DEF, | ||
1778 | focus_range: Some( | 1776 | focus_range: Some( |
1779 | 6..9, | 1777 | 6..9, |
1780 | ), | 1778 | ), |
1779 | name: "Foo", | ||
1780 | kind: TRAIT_DEF, | ||
1781 | container_name: None, | 1781 | container_name: None, |
1782 | description: Some( | 1782 | description: Some( |
1783 | "trait Foo", | 1783 | "trait Foo", |
@@ -1792,11 +1792,11 @@ fn main() { let s<|>t = foo(); } | |||
1792 | 1, | 1792 | 1, |
1793 | ), | 1793 | ), |
1794 | full_range: 13..25, | 1794 | full_range: 13..25, |
1795 | name: "Bar", | ||
1796 | kind: TRAIT_DEF, | ||
1797 | focus_range: Some( | 1795 | focus_range: Some( |
1798 | 19..22, | 1796 | 19..22, |
1799 | ), | 1797 | ), |
1798 | name: "Bar", | ||
1799 | kind: TRAIT_DEF, | ||
1800 | container_name: None, | 1800 | container_name: None, |
1801 | description: Some( | 1801 | description: Some( |
1802 | "trait Bar", | 1802 | "trait Bar", |
@@ -1835,11 +1835,11 @@ fn main() { let s<|>t = foo(); } | |||
1835 | 1, | 1835 | 1, |
1836 | ), | 1836 | ), |
1837 | full_range: 0..15, | 1837 | full_range: 0..15, |
1838 | name: "Foo", | ||
1839 | kind: TRAIT_DEF, | ||
1840 | focus_range: Some( | 1838 | focus_range: Some( |
1841 | 6..9, | 1839 | 6..9, |
1842 | ), | 1840 | ), |
1841 | name: "Foo", | ||
1842 | kind: TRAIT_DEF, | ||
1843 | container_name: None, | 1843 | container_name: None, |
1844 | description: Some( | 1844 | description: Some( |
1845 | "trait Foo", | 1845 | "trait Foo", |
@@ -1854,11 +1854,11 @@ fn main() { let s<|>t = foo(); } | |||
1854 | 1, | 1854 | 1, |
1855 | ), | 1855 | ), |
1856 | full_range: 16..31, | 1856 | full_range: 16..31, |
1857 | name: "Bar", | ||
1858 | kind: TRAIT_DEF, | ||
1859 | focus_range: Some( | 1857 | focus_range: Some( |
1860 | 22..25, | 1858 | 22..25, |
1861 | ), | 1859 | ), |
1860 | name: "Bar", | ||
1861 | kind: TRAIT_DEF, | ||
1862 | container_name: None, | 1862 | container_name: None, |
1863 | description: Some( | 1863 | description: Some( |
1864 | "trait Bar", | 1864 | "trait Bar", |
@@ -1873,11 +1873,11 @@ fn main() { let s<|>t = foo(); } | |||
1873 | 1, | 1873 | 1, |
1874 | ), | 1874 | ), |
1875 | full_range: 32..44, | 1875 | full_range: 32..44, |
1876 | name: "S1", | ||
1877 | kind: STRUCT_DEF, | ||
1878 | focus_range: Some( | 1876 | focus_range: Some( |
1879 | 39..41, | 1877 | 39..41, |
1880 | ), | 1878 | ), |
1879 | name: "S1", | ||
1880 | kind: STRUCT_DEF, | ||
1881 | container_name: None, | 1881 | container_name: None, |
1882 | description: Some( | 1882 | description: Some( |
1883 | "struct S1", | 1883 | "struct S1", |
@@ -1892,11 +1892,11 @@ fn main() { let s<|>t = foo(); } | |||
1892 | 1, | 1892 | 1, |
1893 | ), | 1893 | ), |
1894 | full_range: 45..57, | 1894 | full_range: 45..57, |
1895 | name: "S2", | ||
1896 | kind: STRUCT_DEF, | ||
1897 | focus_range: Some( | 1895 | focus_range: Some( |
1898 | 52..54, | 1896 | 52..54, |
1899 | ), | 1897 | ), |
1898 | name: "S2", | ||
1899 | kind: STRUCT_DEF, | ||
1900 | container_name: None, | 1900 | container_name: None, |
1901 | description: Some( | 1901 | description: Some( |
1902 | "struct S2", | 1902 | "struct S2", |
@@ -1929,11 +1929,11 @@ fn foo(ar<|>g: &impl Foo) {} | |||
1929 | 1, | 1929 | 1, |
1930 | ), | 1930 | ), |
1931 | full_range: 0..12, | 1931 | full_range: 0..12, |
1932 | name: "Foo", | ||
1933 | kind: TRAIT_DEF, | ||
1934 | focus_range: Some( | 1932 | focus_range: Some( |
1935 | 6..9, | 1933 | 6..9, |
1936 | ), | 1934 | ), |
1935 | name: "Foo", | ||
1936 | kind: TRAIT_DEF, | ||
1937 | container_name: None, | 1937 | container_name: None, |
1938 | description: Some( | 1938 | description: Some( |
1939 | "trait Foo", | 1939 | "trait Foo", |
@@ -1969,11 +1969,11 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
1969 | 1, | 1969 | 1, |
1970 | ), | 1970 | ), |
1971 | full_range: 0..12, | 1971 | full_range: 0..12, |
1972 | name: "Foo", | ||
1973 | kind: TRAIT_DEF, | ||
1974 | focus_range: Some( | 1972 | focus_range: Some( |
1975 | 6..9, | 1973 | 6..9, |
1976 | ), | 1974 | ), |
1975 | name: "Foo", | ||
1976 | kind: TRAIT_DEF, | ||
1977 | container_name: None, | 1977 | container_name: None, |
1978 | description: Some( | 1978 | description: Some( |
1979 | "trait Foo", | 1979 | "trait Foo", |
@@ -1988,11 +1988,11 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
1988 | 1, | 1988 | 1, |
1989 | ), | 1989 | ), |
1990 | full_range: 13..28, | 1990 | full_range: 13..28, |
1991 | name: "Bar", | ||
1992 | kind: TRAIT_DEF, | ||
1993 | focus_range: Some( | 1991 | focus_range: Some( |
1994 | 19..22, | 1992 | 19..22, |
1995 | ), | 1993 | ), |
1994 | name: "Bar", | ||
1995 | kind: TRAIT_DEF, | ||
1996 | container_name: None, | 1996 | container_name: None, |
1997 | description: Some( | 1997 | description: Some( |
1998 | "trait Bar", | 1998 | "trait Bar", |
@@ -2007,11 +2007,11 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
2007 | 1, | 2007 | 1, |
2008 | ), | 2008 | ), |
2009 | full_range: 29..39, | 2009 | full_range: 29..39, |
2010 | name: "S", | ||
2011 | kind: STRUCT_DEF, | ||
2012 | focus_range: Some( | 2010 | focus_range: Some( |
2013 | 36..37, | 2011 | 36..37, |
2014 | ), | 2012 | ), |
2013 | name: "S", | ||
2014 | kind: STRUCT_DEF, | ||
2015 | container_name: None, | 2015 | container_name: None, |
2016 | description: Some( | 2016 | description: Some( |
2017 | "struct S", | 2017 | "struct S", |
@@ -2045,11 +2045,11 @@ fn foo(ar<|>g: &impl Foo<S>) {} | |||
2045 | 1, | 2045 | 1, |
2046 | ), | 2046 | ), |
2047 | full_range: 0..15, | 2047 | full_range: 0..15, |
2048 | name: "Foo", | ||
2049 | kind: TRAIT_DEF, | ||
2050 | focus_range: Some( | 2048 | focus_range: Some( |
2051 | 6..9, | 2049 | 6..9, |
2052 | ), | 2050 | ), |
2051 | name: "Foo", | ||
2052 | kind: TRAIT_DEF, | ||
2053 | container_name: None, | 2053 | container_name: None, |
2054 | description: Some( | 2054 | description: Some( |
2055 | "trait Foo", | 2055 | "trait Foo", |
@@ -2064,11 +2064,11 @@ fn foo(ar<|>g: &impl Foo<S>) {} | |||
2064 | 1, | 2064 | 1, |
2065 | ), | 2065 | ), |
2066 | full_range: 16..27, | 2066 | full_range: 16..27, |
2067 | name: "S", | ||
2068 | kind: STRUCT_DEF, | ||
2069 | focus_range: Some( | 2067 | focus_range: Some( |
2070 | 23..24, | 2068 | 23..24, |
2071 | ), | 2069 | ), |
2070 | name: "S", | ||
2071 | kind: STRUCT_DEF, | ||
2072 | container_name: None, | 2072 | container_name: None, |
2073 | description: Some( | 2073 | description: Some( |
2074 | "struct S", | 2074 | "struct S", |
@@ -2107,11 +2107,11 @@ fn main() { let s<|>t = foo(); } | |||
2107 | 1, | 2107 | 1, |
2108 | ), | 2108 | ), |
2109 | full_range: 42..55, | 2109 | full_range: 42..55, |
2110 | name: "B", | ||
2111 | kind: STRUCT_DEF, | ||
2112 | focus_range: Some( | 2110 | focus_range: Some( |
2113 | 49..50, | 2111 | 49..50, |
2114 | ), | 2112 | ), |
2113 | name: "B", | ||
2114 | kind: STRUCT_DEF, | ||
2115 | container_name: None, | 2115 | container_name: None, |
2116 | description: Some( | 2116 | description: Some( |
2117 | "struct B", | 2117 | "struct B", |
@@ -2126,11 +2126,11 @@ fn main() { let s<|>t = foo(); } | |||
2126 | 1, | 2126 | 1, |
2127 | ), | 2127 | ), |
2128 | full_range: 0..12, | 2128 | full_range: 0..12, |
2129 | name: "Foo", | ||
2130 | kind: TRAIT_DEF, | ||
2131 | focus_range: Some( | 2129 | focus_range: Some( |
2132 | 6..9, | 2130 | 6..9, |
2133 | ), | 2131 | ), |
2132 | name: "Foo", | ||
2133 | kind: TRAIT_DEF, | ||
2134 | container_name: None, | 2134 | container_name: None, |
2135 | description: Some( | 2135 | description: Some( |
2136 | "trait Foo", | 2136 | "trait Foo", |
@@ -2163,11 +2163,11 @@ fn foo(ar<|>g: &dyn Foo) {} | |||
2163 | 1, | 2163 | 1, |
2164 | ), | 2164 | ), |
2165 | full_range: 0..12, | 2165 | full_range: 0..12, |
2166 | name: "Foo", | ||
2167 | kind: TRAIT_DEF, | ||
2168 | focus_range: Some( | 2166 | focus_range: Some( |
2169 | 6..9, | 2167 | 6..9, |
2170 | ), | 2168 | ), |
2169 | name: "Foo", | ||
2170 | kind: TRAIT_DEF, | ||
2171 | container_name: None, | 2171 | container_name: None, |
2172 | description: Some( | 2172 | description: Some( |
2173 | "trait Foo", | 2173 | "trait Foo", |
@@ -2201,11 +2201,11 @@ fn foo(ar<|>g: &dyn Foo<S>) {} | |||
2201 | 1, | 2201 | 1, |
2202 | ), | 2202 | ), |
2203 | full_range: 0..15, | 2203 | full_range: 0..15, |
2204 | name: "Foo", | ||
2205 | kind: TRAIT_DEF, | ||
2206 | focus_range: Some( | 2204 | focus_range: Some( |
2207 | 6..9, | 2205 | 6..9, |
2208 | ), | 2206 | ), |
2207 | name: "Foo", | ||
2208 | kind: TRAIT_DEF, | ||
2209 | container_name: None, | 2209 | container_name: None, |
2210 | description: Some( | 2210 | description: Some( |
2211 | "trait Foo", | 2211 | "trait Foo", |
@@ -2220,11 +2220,11 @@ fn foo(ar<|>g: &dyn Foo<S>) {} | |||
2220 | 1, | 2220 | 1, |
2221 | ), | 2221 | ), |
2222 | full_range: 16..27, | 2222 | full_range: 16..27, |
2223 | name: "S", | ||
2224 | kind: STRUCT_DEF, | ||
2225 | focus_range: Some( | 2223 | focus_range: Some( |
2226 | 23..24, | 2224 | 23..24, |
2227 | ), | 2225 | ), |
2226 | name: "S", | ||
2227 | kind: STRUCT_DEF, | ||
2228 | container_name: None, | 2228 | container_name: None, |
2229 | description: Some( | 2229 | description: Some( |
2230 | "struct S", | 2230 | "struct S", |
@@ -2261,11 +2261,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2261 | 1, | 2261 | 1, |
2262 | ), | 2262 | ), |
2263 | full_range: 0..21, | 2263 | full_range: 0..21, |
2264 | name: "ImplTrait", | ||
2265 | kind: TRAIT_DEF, | ||
2266 | focus_range: Some( | 2264 | focus_range: Some( |
2267 | 6..15, | 2265 | 6..15, |
2268 | ), | 2266 | ), |
2267 | name: "ImplTrait", | ||
2268 | kind: TRAIT_DEF, | ||
2269 | container_name: None, | 2269 | container_name: None, |
2270 | description: Some( | 2270 | description: Some( |
2271 | "trait ImplTrait", | 2271 | "trait ImplTrait", |
@@ -2280,11 +2280,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2280 | 1, | 2280 | 1, |
2281 | ), | 2281 | ), |
2282 | full_range: 43..57, | 2282 | full_range: 43..57, |
2283 | name: "B", | ||
2284 | kind: STRUCT_DEF, | ||
2285 | focus_range: Some( | 2283 | focus_range: Some( |
2286 | 50..51, | 2284 | 50..51, |
2287 | ), | 2285 | ), |
2286 | name: "B", | ||
2287 | kind: STRUCT_DEF, | ||
2288 | container_name: None, | 2288 | container_name: None, |
2289 | description: Some( | 2289 | description: Some( |
2290 | "struct B", | 2290 | "struct B", |
@@ -2299,11 +2299,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2299 | 1, | 2299 | 1, |
2300 | ), | 2300 | ), |
2301 | full_range: 22..42, | 2301 | full_range: 22..42, |
2302 | name: "DynTrait", | ||
2303 | kind: TRAIT_DEF, | ||
2304 | focus_range: Some( | 2302 | focus_range: Some( |
2305 | 28..36, | 2303 | 28..36, |
2306 | ), | 2304 | ), |
2305 | name: "DynTrait", | ||
2306 | kind: TRAIT_DEF, | ||
2307 | container_name: None, | 2307 | container_name: None, |
2308 | description: Some( | 2308 | description: Some( |
2309 | "trait DynTrait", | 2309 | "trait DynTrait", |
@@ -2318,11 +2318,11 @@ fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} | |||
2318 | 1, | 2318 | 1, |
2319 | ), | 2319 | ), |
2320 | full_range: 58..69, | 2320 | full_range: 58..69, |
2321 | name: "S", | ||
2322 | kind: STRUCT_DEF, | ||
2323 | focus_range: Some( | 2321 | focus_range: Some( |
2324 | 65..66, | 2322 | 65..66, |
2325 | ), | 2323 | ), |
2324 | name: "S", | ||
2325 | kind: STRUCT_DEF, | ||
2326 | container_name: None, | 2326 | container_name: None, |
2327 | description: Some( | 2327 | description: Some( |
2328 | "struct S", | 2328 | "struct S", |
@@ -2366,11 +2366,11 @@ fn main() { let s<|>t = test().get(); } | |||
2366 | 1, | 2366 | 1, |
2367 | ), | 2367 | ), |
2368 | full_range: 0..62, | 2368 | full_range: 0..62, |
2369 | name: "Foo", | ||
2370 | kind: TRAIT_DEF, | ||
2371 | focus_range: Some( | 2369 | focus_range: Some( |
2372 | 6..9, | 2370 | 6..9, |
2373 | ), | 2371 | ), |
2372 | name: "Foo", | ||
2373 | kind: TRAIT_DEF, | ||
2374 | container_name: None, | 2374 | container_name: None, |
2375 | description: Some( | 2375 | description: Some( |
2376 | "trait Foo", | 2376 | "trait Foo", |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 3cbae8a45..43a5e29b5 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -1,14 +1,16 @@ | |||
1 | use hir::{Adt, HirDisplay, Semantics, Type}; | 1 | use hir::{Adt, Callable, HirDisplay, Semantics, Type}; |
2 | use ra_ide_db::RootDatabase; | 2 | use ra_ide_db::RootDatabase; |
3 | use ra_prof::profile; | 3 | use ra_prof::profile; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, | 5 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, |
6 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, | 6 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T, |
7 | }; | 7 | }; |
8 | |||
9 | use crate::{FileId, FunctionSignature}; | ||
10 | use stdx::to_lower_snake_case; | 8 | use stdx::to_lower_snake_case; |
11 | 9 | ||
10 | use crate::FileId; | ||
11 | use ast::NameOwner; | ||
12 | use either::Either; | ||
13 | |||
12 | #[derive(Clone, Debug, PartialEq, Eq)] | 14 | #[derive(Clone, Debug, PartialEq, Eq)] |
13 | pub struct InlayHintsConfig { | 15 | pub struct InlayHintsConfig { |
14 | pub type_hints: bool, | 16 | pub type_hints: bool, |
@@ -150,23 +152,26 @@ fn get_param_name_hints( | |||
150 | _ => return None, | 152 | _ => return None, |
151 | }; | 153 | }; |
152 | 154 | ||
153 | let fn_signature = get_fn_signature(sema, &expr)?; | 155 | let callable = get_callable(sema, &expr)?; |
154 | let n_params_to_skip = | 156 | let hints = callable |
155 | if fn_signature.has_self_param && matches!(&expr, ast::Expr::MethodCallExpr(_)) { | 157 | .params(sema.db) |
156 | 1 | 158 | .into_iter() |
157 | } else { | ||
158 | 0 | ||
159 | }; | ||
160 | let hints = fn_signature | ||
161 | .parameter_names | ||
162 | .iter() | ||
163 | .skip(n_params_to_skip) | ||
164 | .zip(args) | 159 | .zip(args) |
165 | .filter(|(param, arg)| should_show_param_name_hint(sema, &fn_signature, param, &arg)) | 160 | .filter_map(|((param, _ty), arg)| match param? { |
161 | Either::Left(self_param) => Some((self_param.to_string(), arg)), | ||
162 | Either::Right(pat) => { | ||
163 | let param_name = match pat { | ||
164 | ast::Pat::BindPat(it) => it.name()?.to_string(), | ||
165 | it => it.to_string(), | ||
166 | }; | ||
167 | Some((param_name, arg)) | ||
168 | } | ||
169 | }) | ||
170 | .filter(|(param_name, arg)| should_show_param_name_hint(sema, &callable, ¶m_name, &arg)) | ||
166 | .map(|(param_name, arg)| InlayHint { | 171 | .map(|(param_name, arg)| InlayHint { |
167 | range: arg.syntax().text_range(), | 172 | range: arg.syntax().text_range(), |
168 | kind: InlayKind::ParameterHint, | 173 | kind: InlayKind::ParameterHint, |
169 | label: param_name.into(), | 174 | label: param_name.to_string().into(), |
170 | }); | 175 | }); |
171 | 176 | ||
172 | acc.extend(hints); | 177 | acc.extend(hints); |
@@ -250,28 +255,28 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ | |||
250 | 255 | ||
251 | fn should_show_param_name_hint( | 256 | fn should_show_param_name_hint( |
252 | sema: &Semantics<RootDatabase>, | 257 | sema: &Semantics<RootDatabase>, |
253 | fn_signature: &FunctionSignature, | 258 | callable: &Callable, |
254 | param_name: &str, | 259 | param_name: &str, |
255 | argument: &ast::Expr, | 260 | argument: &ast::Expr, |
256 | ) -> bool { | 261 | ) -> bool { |
257 | let param_name = param_name.trim_start_matches('_'); | 262 | let param_name = param_name.trim_start_matches('_'); |
263 | let fn_name = match callable.kind() { | ||
264 | hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()), | ||
265 | hir::CallableKind::TupleStruct(_) | ||
266 | | hir::CallableKind::TupleEnumVariant(_) | ||
267 | | hir::CallableKind::Closure => None, | ||
268 | }; | ||
258 | if param_name.is_empty() | 269 | if param_name.is_empty() |
259 | || Some(param_name) == fn_signature.name.as_ref().map(|s| s.trim_start_matches('_')) | 270 | || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_')) |
260 | || is_argument_similar_to_param_name(sema, argument, param_name) | 271 | || is_argument_similar_to_param_name(sema, argument, param_name) |
261 | || param_name.starts_with("ra_fixture") | 272 | || param_name.starts_with("ra_fixture") |
262 | { | 273 | { |
263 | return false; | 274 | return false; |
264 | } | 275 | } |
265 | 276 | ||
266 | let parameters_len = if fn_signature.has_self_param { | ||
267 | fn_signature.parameters.len() - 1 | ||
268 | } else { | ||
269 | fn_signature.parameters.len() | ||
270 | }; | ||
271 | |||
272 | // avoid displaying hints for common functions like map, filter, etc. | 277 | // avoid displaying hints for common functions like map, filter, etc. |
273 | // or other obvious words used in std | 278 | // or other obvious words used in std |
274 | !(parameters_len == 1 && is_obvious_param(param_name)) | 279 | !(callable.n_params() == 1 && is_obvious_param(param_name)) |
275 | } | 280 | } |
276 | 281 | ||
277 | fn is_argument_similar_to_param_name( | 282 | fn is_argument_similar_to_param_name( |
@@ -318,27 +323,10 @@ fn is_obvious_param(param_name: &str) -> bool { | |||
318 | param_name.len() == 1 || is_obvious_param_name | 323 | param_name.len() == 1 || is_obvious_param_name |
319 | } | 324 | } |
320 | 325 | ||
321 | fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { | 326 | fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<Callable> { |
322 | match expr { | 327 | match expr { |
323 | ast::Expr::CallExpr(expr) => { | 328 | ast::Expr::CallExpr(expr) => sema.type_of_expr(&expr.expr()?)?.as_callable(sema.db), |
324 | // FIXME: Type::as_callable is broken for closures | 329 | ast::Expr::MethodCallExpr(expr) => sema.resolve_method_call_as_callable(expr), |
325 | let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; | ||
326 | match callable_def { | ||
327 | hir::CallableDefId::FunctionId(it) => { | ||
328 | Some(FunctionSignature::from_hir(sema.db, it.into())) | ||
329 | } | ||
330 | hir::CallableDefId::StructId(it) => { | ||
331 | FunctionSignature::from_struct(sema.db, it.into()) | ||
332 | } | ||
333 | hir::CallableDefId::EnumVariantId(it) => { | ||
334 | FunctionSignature::from_enum_variant(sema.db, it.into()) | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | ast::Expr::MethodCallExpr(expr) => { | ||
339 | let fn_def = sema.resolve_method_call(&expr)?; | ||
340 | Some(FunctionSignature::from_hir(sema.db, fn_def)) | ||
341 | } | ||
342 | _ => None, | 330 | _ => None, |
343 | } | 331 | } |
344 | } | 332 | } |
@@ -360,7 +348,7 @@ mod tests { | |||
360 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); | 348 | let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap(); |
361 | let actual = | 349 | let actual = |
362 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); | 350 | inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>(); |
363 | assert_eq!(expected, actual); | 351 | assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual); |
364 | } | 352 | } |
365 | 353 | ||
366 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { | 354 | fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 5d1f64e19..353f430ff 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -19,29 +19,31 @@ pub mod mock_analysis; | |||
19 | 19 | ||
20 | mod markup; | 20 | mod markup; |
21 | mod prime_caches; | 21 | mod prime_caches; |
22 | mod status; | 22 | mod display; |
23 | |||
24 | mod call_hierarchy; | ||
25 | mod call_info; | ||
23 | mod completion; | 26 | mod completion; |
24 | mod runnables; | 27 | mod diagnostics; |
28 | mod expand_macro; | ||
29 | mod extend_selection; | ||
30 | mod file_structure; | ||
31 | mod folding_ranges; | ||
25 | mod goto_definition; | 32 | mod goto_definition; |
26 | mod goto_type_definition; | ||
27 | mod goto_implementation; | 33 | mod goto_implementation; |
28 | mod extend_selection; | 34 | mod goto_type_definition; |
29 | mod hover; | 35 | mod hover; |
30 | mod call_hierarchy; | 36 | mod inlay_hints; |
31 | mod call_info; | 37 | mod join_lines; |
32 | mod syntax_highlighting; | 38 | mod matching_brace; |
33 | mod parent_module; | 39 | mod parent_module; |
34 | mod references; | 40 | mod references; |
35 | mod diagnostics; | 41 | mod runnables; |
42 | mod ssr; | ||
43 | mod status; | ||
44 | mod syntax_highlighting; | ||
36 | mod syntax_tree; | 45 | mod syntax_tree; |
37 | mod folding_ranges; | ||
38 | mod join_lines; | ||
39 | mod typing; | 46 | mod typing; |
40 | mod matching_brace; | ||
41 | mod display; | ||
42 | mod inlay_hints; | ||
43 | mod expand_macro; | ||
44 | mod ssr; | ||
45 | 47 | ||
46 | use std::sync::Arc; | 48 | use std::sync::Arc; |
47 | 49 | ||
@@ -65,8 +67,9 @@ pub use crate::{ | |||
65 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, | 67 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, |
66 | }, | 68 | }, |
67 | diagnostics::Severity, | 69 | diagnostics::Severity, |
68 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, | 70 | display::NavigationTarget, |
69 | expand_macro::ExpandedMacro, | 71 | expand_macro::ExpandedMacro, |
72 | file_structure::StructureNode, | ||
70 | folding_ranges::{Fold, FoldKind}, | 73 | folding_ranges::{Fold, FoldKind}, |
71 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, | 74 | hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, |
72 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, | 75 | inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, |
@@ -323,7 +326,7 @@ impl Analysis { | |||
323 | /// Returns a tree representation of symbols in the file. Useful to draw a | 326 | /// Returns a tree representation of symbols in the file. Useful to draw a |
324 | /// file outline. | 327 | /// file outline. |
325 | pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> { | 328 | pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> { |
326 | self.with_db(|db| file_structure(&db.parse(file_id).tree())) | 329 | self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree())) |
327 | } | 330 | } |
328 | 331 | ||
329 | /// Returns a list of the places in the file where type hints can be displayed. | 332 | /// Returns a list of the places in the file where type hints can be displayed. |
@@ -542,8 +545,8 @@ mod tests { | |||
542 | 545 | ||
543 | let s = symbols.pop().unwrap(); | 546 | let s = symbols.pop().unwrap(); |
544 | 547 | ||
545 | assert_eq!(s.name(), "FooInner"); | 548 | assert_eq!(s.name, "FooInner"); |
546 | assert!(s.container_name().is_none()); | 549 | assert!(s.container_name.is_none()); |
547 | } | 550 | } |
548 | 551 | ||
549 | #[test] | 552 | #[test] |
@@ -558,8 +561,8 @@ fn foo() { | |||
558 | 561 | ||
559 | let s = symbols.pop().unwrap(); | 562 | let s = symbols.pop().unwrap(); |
560 | 563 | ||
561 | assert_eq!(s.name(), "FooInner"); | 564 | assert_eq!(s.name, "FooInner"); |
562 | assert_eq!(s.container_name(), Some(&SmolStr::new("foo"))); | 565 | assert_eq!(s.container_name, Some(SmolStr::new("foo"))); |
563 | 566 | ||
564 | let code = r#" | 567 | let code = r#" |
565 | mod foo { | 568 | mod foo { |
@@ -571,8 +574,8 @@ mod foo { | |||
571 | 574 | ||
572 | let s = symbols.pop().unwrap(); | 575 | let s = symbols.pop().unwrap(); |
573 | 576 | ||
574 | assert_eq!(s.name(), "FooInner"); | 577 | assert_eq!(s.name, "FooInner"); |
575 | assert_eq!(s.container_name(), Some(&SmolStr::new("foo"))); | 578 | assert_eq!(s.container_name, Some(SmolStr::new("foo"))); |
576 | } | 579 | } |
577 | 580 | ||
578 | #[test] | 581 | #[test] |
@@ -585,8 +588,8 @@ struct Foo; | |||
585 | 588 | ||
586 | let symbols = get_symbols_matching(code, "Foo"); | 589 | let symbols = get_symbols_matching(code, "Foo"); |
587 | 590 | ||
588 | let fn_match = symbols.iter().find(|s| s.name() == "foo").map(|s| s.kind()); | 591 | let fn_match = symbols.iter().find(|s| s.name == "foo").map(|s| s.kind); |
589 | let struct_match = symbols.iter().find(|s| s.name() == "Foo").map(|s| s.kind()); | 592 | let struct_match = symbols.iter().find(|s| s.name == "Foo").map(|s| s.kind); |
590 | 593 | ||
591 | assert_eq!(fn_match, Some(FN_DEF)); | 594 | assert_eq!(fn_match, Some(FN_DEF)); |
592 | assert_eq!(struct_match, Some(STRUCT_DEF)); | 595 | assert_eq!(struct_match, Some(STRUCT_DEF)); |
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index c2b0d5efe..fe1c074d1 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -74,8 +74,8 @@ impl IntoIterator for ReferenceSearchResult { | |||
74 | let mut v = Vec::with_capacity(self.len()); | 74 | let mut v = Vec::with_capacity(self.len()); |
75 | v.push(Reference { | 75 | v.push(Reference { |
76 | file_range: FileRange { | 76 | file_range: FileRange { |
77 | file_id: self.declaration.nav.file_id(), | 77 | file_id: self.declaration.nav.file_id, |
78 | range: self.declaration.nav.range(), | 78 | range: self.declaration.nav.focus_or_full_range(), |
79 | }, | 79 | }, |
80 | kind: self.declaration.kind, | 80 | kind: self.declaration.kind, |
81 | access: self.declaration.access, | 81 | access: self.declaration.access, |
@@ -112,7 +112,7 @@ pub(crate) fn find_all_refs( | |||
112 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) | 112 | .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) |
113 | .collect(); | 113 | .collect(); |
114 | 114 | ||
115 | let decl_range = def.try_to_nav(sema.db)?.range(); | 115 | let decl_range = def.try_to_nav(sema.db)?.focus_or_full_range(); |
116 | 116 | ||
117 | let declaration = Declaration { | 117 | let declaration = Declaration { |
118 | nav: def.try_to_nav(sema.db)?, | 118 | nav: def.try_to_nav(sema.db)?, |
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs index ed15d6494..0994beec5 100644 --- a/crates/ra_ide/src/runnables.rs +++ b/crates/ra_ide/src/runnables.rs | |||
@@ -299,11 +299,11 @@ fn bench() {} | |||
299 | 1, | 299 | 1, |
300 | ), | 300 | ), |
301 | full_range: 1..13, | 301 | full_range: 1..13, |
302 | name: "main", | ||
303 | kind: FN_DEF, | ||
304 | focus_range: Some( | 302 | focus_range: Some( |
305 | 4..8, | 303 | 4..8, |
306 | ), | 304 | ), |
305 | name: "main", | ||
306 | kind: FN_DEF, | ||
307 | container_name: None, | 307 | container_name: None, |
308 | description: None, | 308 | description: None, |
309 | docs: None, | 309 | docs: None, |
@@ -317,11 +317,11 @@ fn bench() {} | |||
317 | 1, | 317 | 1, |
318 | ), | 318 | ), |
319 | full_range: 15..39, | 319 | full_range: 15..39, |
320 | name: "test_foo", | ||
321 | kind: FN_DEF, | ||
322 | focus_range: Some( | 320 | focus_range: Some( |
323 | 26..34, | 321 | 26..34, |
324 | ), | 322 | ), |
323 | name: "test_foo", | ||
324 | kind: FN_DEF, | ||
325 | container_name: None, | 325 | container_name: None, |
326 | description: None, | 326 | description: None, |
327 | docs: None, | 327 | docs: None, |
@@ -342,11 +342,11 @@ fn bench() {} | |||
342 | 1, | 342 | 1, |
343 | ), | 343 | ), |
344 | full_range: 41..75, | 344 | full_range: 41..75, |
345 | name: "test_foo", | ||
346 | kind: FN_DEF, | ||
347 | focus_range: Some( | 345 | focus_range: Some( |
348 | 62..70, | 346 | 62..70, |
349 | ), | 347 | ), |
348 | name: "test_foo", | ||
349 | kind: FN_DEF, | ||
350 | container_name: None, | 350 | container_name: None, |
351 | description: None, | 351 | description: None, |
352 | docs: None, | 352 | docs: None, |
@@ -367,11 +367,11 @@ fn bench() {} | |||
367 | 1, | 367 | 1, |
368 | ), | 368 | ), |
369 | full_range: 77..99, | 369 | full_range: 77..99, |
370 | name: "bench", | ||
371 | kind: FN_DEF, | ||
372 | focus_range: Some( | 370 | focus_range: Some( |
373 | 89..94, | 371 | 89..94, |
374 | ), | 372 | ), |
373 | name: "bench", | ||
374 | kind: FN_DEF, | ||
375 | container_name: None, | 375 | container_name: None, |
376 | description: None, | 376 | description: None, |
377 | docs: None, | 377 | docs: None, |
@@ -410,11 +410,11 @@ fn foo() {} | |||
410 | 1, | 410 | 1, |
411 | ), | 411 | ), |
412 | full_range: 1..13, | 412 | full_range: 1..13, |
413 | name: "main", | ||
414 | kind: FN_DEF, | ||
415 | focus_range: Some( | 413 | focus_range: Some( |
416 | 4..8, | 414 | 4..8, |
417 | ), | 415 | ), |
416 | name: "main", | ||
417 | kind: FN_DEF, | ||
418 | container_name: None, | 418 | container_name: None, |
419 | description: None, | 419 | description: None, |
420 | docs: None, | 420 | docs: None, |
@@ -428,9 +428,9 @@ fn foo() {} | |||
428 | 1, | 428 | 1, |
429 | ), | 429 | ), |
430 | full_range: 15..57, | 430 | full_range: 15..57, |
431 | focus_range: None, | ||
431 | name: "foo", | 432 | name: "foo", |
432 | kind: FN_DEF, | 433 | kind: FN_DEF, |
433 | focus_range: None, | ||
434 | container_name: None, | 434 | container_name: None, |
435 | description: None, | 435 | description: None, |
436 | docs: None, | 436 | docs: None, |
@@ -472,11 +472,11 @@ impl Data { | |||
472 | 1, | 472 | 1, |
473 | ), | 473 | ), |
474 | full_range: 1..13, | 474 | full_range: 1..13, |
475 | name: "main", | ||
476 | kind: FN_DEF, | ||
477 | focus_range: Some( | 475 | focus_range: Some( |
478 | 4..8, | 476 | 4..8, |
479 | ), | 477 | ), |
478 | name: "main", | ||
479 | kind: FN_DEF, | ||
480 | container_name: None, | 480 | container_name: None, |
481 | description: None, | 481 | description: None, |
482 | docs: None, | 482 | docs: None, |
@@ -490,9 +490,9 @@ impl Data { | |||
490 | 1, | 490 | 1, |
491 | ), | 491 | ), |
492 | full_range: 44..98, | 492 | full_range: 44..98, |
493 | focus_range: None, | ||
493 | name: "foo", | 494 | name: "foo", |
494 | kind: FN_DEF, | 495 | kind: FN_DEF, |
495 | focus_range: None, | ||
496 | container_name: None, | 496 | container_name: None, |
497 | description: None, | 497 | description: None, |
498 | docs: None, | 498 | docs: None, |
@@ -529,11 +529,11 @@ mod test_mod { | |||
529 | 1, | 529 | 1, |
530 | ), | 530 | ), |
531 | full_range: 1..51, | 531 | full_range: 1..51, |
532 | name: "test_mod", | ||
533 | kind: MODULE, | ||
534 | focus_range: Some( | 532 | focus_range: Some( |
535 | 5..13, | 533 | 5..13, |
536 | ), | 534 | ), |
535 | name: "test_mod", | ||
536 | kind: MODULE, | ||
537 | container_name: None, | 537 | container_name: None, |
538 | description: None, | 538 | description: None, |
539 | docs: None, | 539 | docs: None, |
@@ -549,11 +549,11 @@ mod test_mod { | |||
549 | 1, | 549 | 1, |
550 | ), | 550 | ), |
551 | full_range: 20..49, | 551 | full_range: 20..49, |
552 | name: "test_foo1", | ||
553 | kind: FN_DEF, | ||
554 | focus_range: Some( | 552 | focus_range: Some( |
555 | 35..44, | 553 | 35..44, |
556 | ), | 554 | ), |
555 | name: "test_foo1", | ||
556 | kind: FN_DEF, | ||
557 | container_name: None, | 557 | container_name: None, |
558 | description: None, | 558 | description: None, |
559 | docs: None, | 559 | docs: None, |
@@ -595,11 +595,11 @@ mod foo { | |||
595 | 1, | 595 | 1, |
596 | ), | 596 | ), |
597 | full_range: 15..77, | 597 | full_range: 15..77, |
598 | name: "test_mod", | ||
599 | kind: MODULE, | ||
600 | focus_range: Some( | 598 | focus_range: Some( |
601 | 19..27, | 599 | 19..27, |
602 | ), | 600 | ), |
601 | name: "test_mod", | ||
602 | kind: MODULE, | ||
603 | container_name: None, | 603 | container_name: None, |
604 | description: None, | 604 | description: None, |
605 | docs: None, | 605 | docs: None, |
@@ -615,11 +615,11 @@ mod foo { | |||
615 | 1, | 615 | 1, |
616 | ), | 616 | ), |
617 | full_range: 38..71, | 617 | full_range: 38..71, |
618 | name: "test_foo1", | ||
619 | kind: FN_DEF, | ||
620 | focus_range: Some( | 618 | focus_range: Some( |
621 | 57..66, | 619 | 57..66, |
622 | ), | 620 | ), |
621 | name: "test_foo1", | ||
622 | kind: FN_DEF, | ||
623 | container_name: None, | 623 | container_name: None, |
624 | description: None, | 624 | description: None, |
625 | docs: None, | 625 | docs: None, |
@@ -663,11 +663,11 @@ mod foo { | |||
663 | 1, | 663 | 1, |
664 | ), | 664 | ), |
665 | full_range: 33..107, | 665 | full_range: 33..107, |
666 | name: "test_mod", | ||
667 | kind: MODULE, | ||
668 | focus_range: Some( | 666 | focus_range: Some( |
669 | 37..45, | 667 | 37..45, |
670 | ), | 668 | ), |
669 | name: "test_mod", | ||
670 | kind: MODULE, | ||
671 | container_name: None, | 671 | container_name: None, |
672 | description: None, | 672 | description: None, |
673 | docs: None, | 673 | docs: None, |
@@ -683,11 +683,11 @@ mod foo { | |||
683 | 1, | 683 | 1, |
684 | ), | 684 | ), |
685 | full_range: 60..97, | 685 | full_range: 60..97, |
686 | name: "test_foo1", | ||
687 | kind: FN_DEF, | ||
688 | focus_range: Some( | 686 | focus_range: Some( |
689 | 83..92, | 687 | 83..92, |
690 | ), | 688 | ), |
689 | name: "test_foo1", | ||
690 | kind: FN_DEF, | ||
691 | container_name: None, | 691 | container_name: None, |
692 | description: None, | 692 | description: None, |
693 | docs: None, | 693 | docs: None, |
@@ -726,11 +726,11 @@ fn test_foo1() {} | |||
726 | 1, | 726 | 1, |
727 | ), | 727 | ), |
728 | full_range: 1..50, | 728 | full_range: 1..50, |
729 | name: "test_foo1", | ||
730 | kind: FN_DEF, | ||
731 | focus_range: Some( | 729 | focus_range: Some( |
732 | 36..45, | 730 | 36..45, |
733 | ), | 731 | ), |
732 | name: "test_foo1", | ||
733 | kind: FN_DEF, | ||
734 | container_name: None, | 734 | container_name: None, |
735 | description: None, | 735 | description: None, |
736 | docs: None, | 736 | docs: None, |
@@ -774,11 +774,11 @@ fn test_foo1() {} | |||
774 | 1, | 774 | 1, |
775 | ), | 775 | ), |
776 | full_range: 1..72, | 776 | full_range: 1..72, |
777 | name: "test_foo1", | ||
778 | kind: FN_DEF, | ||
779 | focus_range: Some( | 777 | focus_range: Some( |
780 | 58..67, | 778 | 58..67, |
781 | ), | 779 | ), |
780 | name: "test_foo1", | ||
781 | kind: FN_DEF, | ||
782 | container_name: None, | 782 | container_name: None, |
783 | description: None, | 783 | description: None, |
784 | docs: None, | 784 | docs: None, |
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs index 83776d2b6..d3ce744b4 100644 --- a/crates/ra_ide/src/typing.rs +++ b/crates/ra_ide/src/typing.rs | |||
@@ -39,7 +39,6 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>"; | |||
39 | // Some features trigger on typing certain characters: | 39 | // Some features trigger on typing certain characters: |
40 | // | 40 | // |
41 | // - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression | 41 | // - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression |
42 | // - Enter inside comments automatically inserts `///` | ||
43 | // - typing `.` in a chain method call auto-indents | 42 | // - typing `.` in a chain method call auto-indents |
44 | pub(crate) fn on_char_typed( | 43 | pub(crate) fn on_char_typed( |
45 | db: &RootDatabase, | 44 | db: &RootDatabase, |
diff --git a/crates/ra_ide/src/typing/on_enter.rs b/crates/ra_ide/src/typing/on_enter.rs index 2faaa8ff0..143b1ae41 100644 --- a/crates/ra_ide/src/typing/on_enter.rs +++ b/crates/ra_ide/src/typing/on_enter.rs | |||
@@ -7,10 +7,31 @@ use ra_syntax::{ | |||
7 | ast::{self, AstToken}, | 7 | ast::{self, AstToken}, |
8 | AstNode, SmolStr, SourceFile, | 8 | AstNode, SmolStr, SourceFile, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxToken, TextSize, TokenAtOffset, | 10 | SyntaxToken, TextRange, TextSize, TokenAtOffset, |
11 | }; | 11 | }; |
12 | use ra_text_edit::TextEdit; | 12 | use ra_text_edit::TextEdit; |
13 | use test_utils::mark; | ||
13 | 14 | ||
15 | // Feature: On Enter | ||
16 | // | ||
17 | // rust-analyzer can override kbd:[Enter] key to make it smarter: | ||
18 | // | ||
19 | // - kbd:[Enter] inside triple-slash comments automatically inserts `///` | ||
20 | // - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//` | ||
21 | // | ||
22 | // This action needs to be assigned to shortcut explicitly. | ||
23 | // | ||
24 | // VS Code:: | ||
25 | // | ||
26 | // Add the following to `keybindings.json`: | ||
27 | // [source,json] | ||
28 | // ---- | ||
29 | // { | ||
30 | // "key": "Enter", | ||
31 | // "command": "rust-analyzer.onEnter", | ||
32 | // "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" | ||
33 | // } | ||
34 | // ---- | ||
14 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { | 35 | pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { |
15 | let parse = db.parse(position.file_id); | 36 | let parse = db.parse(position.file_id); |
16 | let file = parse.tree(); | 37 | let file = parse.tree(); |
@@ -30,15 +51,25 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text | |||
30 | return None; | 51 | return None; |
31 | } | 52 | } |
32 | 53 | ||
54 | let mut remove_last_space = false; | ||
33 | // Continuing single-line non-doc comments (like this one :) ) is annoying | 55 | // Continuing single-line non-doc comments (like this one :) ) is annoying |
34 | if prefix == "//" && comment_range.end() == position.offset && !followed_by_comment(&comment) { | 56 | if prefix == "//" && comment_range.end() == position.offset { |
35 | return None; | 57 | if comment.text().ends_with(' ') { |
58 | mark::hit!(continues_end_of_line_comment_with_space); | ||
59 | remove_last_space = true; | ||
60 | } else if !followed_by_comment(&comment) { | ||
61 | return None; | ||
62 | } | ||
36 | } | 63 | } |
37 | 64 | ||
38 | let indent = node_indent(&file, comment.syntax())?; | 65 | let indent = node_indent(&file, comment.syntax())?; |
39 | let inserted = format!("\n{}{} $0", indent, prefix); | 66 | let inserted = format!("\n{}{} $0", indent, prefix); |
40 | let edit = TextEdit::insert(position.offset, inserted); | 67 | let delete = if remove_last_space { |
41 | 68 | TextRange::new(position.offset - TextSize::of(' '), position.offset) | |
69 | } else { | ||
70 | TextRange::empty(position.offset) | ||
71 | }; | ||
72 | let edit = TextEdit::replace(delete, inserted); | ||
42 | Some(edit) | 73 | Some(edit) |
43 | } | 74 | } |
44 | 75 | ||
@@ -75,10 +106,10 @@ fn node_indent(file: &SourceFile, token: &SyntaxToken) -> Option<SmolStr> { | |||
75 | 106 | ||
76 | #[cfg(test)] | 107 | #[cfg(test)] |
77 | mod tests { | 108 | mod tests { |
78 | use test_utils::assert_eq_text; | 109 | use stdx::trim_indent; |
110 | use test_utils::{assert_eq_text, mark}; | ||
79 | 111 | ||
80 | use crate::mock_analysis::analysis_and_position; | 112 | use crate::mock_analysis::analysis_and_position; |
81 | use stdx::trim_indent; | ||
82 | 113 | ||
83 | fn apply_on_enter(before: &str) -> Option<String> { | 114 | fn apply_on_enter(before: &str) -> Option<String> { |
84 | let (analysis, position) = analysis_and_position(&before); | 115 | let (analysis, position) = analysis_and_position(&before); |
@@ -192,7 +223,7 @@ fn main() { | |||
192 | } | 223 | } |
193 | 224 | ||
194 | #[test] | 225 | #[test] |
195 | fn does_not_continue_end_of_code_comment() { | 226 | fn does_not_continue_end_of_line_comment() { |
196 | do_check_noop( | 227 | do_check_noop( |
197 | r" | 228 | r" |
198 | fn main() { | 229 | fn main() { |
@@ -202,4 +233,24 @@ fn main() { | |||
202 | ", | 233 | ", |
203 | ); | 234 | ); |
204 | } | 235 | } |
236 | |||
237 | #[test] | ||
238 | fn continues_end_of_line_comment_with_space() { | ||
239 | mark::check!(continues_end_of_line_comment_with_space); | ||
240 | do_check( | ||
241 | r#" | ||
242 | fn main() { | ||
243 | // Fix me <|> | ||
244 | let x = 1 + 1; | ||
245 | } | ||
246 | "#, | ||
247 | r#" | ||
248 | fn main() { | ||
249 | // Fix me | ||
250 | // $0 | ||
251 | let x = 1 + 1; | ||
252 | } | ||
253 | "#, | ||
254 | ); | ||
255 | } | ||
205 | } | 256 | } |