diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/change.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_postfix.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_scope.rs | 62 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 398 | ||||
-rw-r--r-- | crates/ra_ide_api/src/feature_flags.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 19 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_type_definition.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 220 | ||||
-rw-r--r-- | crates/ra_ide_api/src/impls.rs | 11 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references.rs | 15 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references/classify.rs | 22 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references/name_definition.rs | 41 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references/search_scope.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/src/snapshots/rainbow_highlighting.html | 12 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 168 |
17 files changed, 501 insertions, 492 deletions
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index 4416421ae..010b45141 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs | |||
@@ -276,7 +276,7 @@ impl RootDatabase { | |||
276 | 276 | ||
277 | self.query(hir::db::ExprScopesQuery).sweep(sweep); | 277 | self.query(hir::db::ExprScopesQuery).sweep(sweep); |
278 | self.query(hir::db::InferQuery).sweep(sweep); | 278 | self.query(hir::db::InferQuery).sweep(sweep); |
279 | self.query(hir::db::BodyHirQuery).sweep(sweep); | 279 | self.query(hir::db::BodyQuery).sweep(sweep); |
280 | } | 280 | } |
281 | 281 | ||
282 | pub(crate) fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { | 282 | pub(crate) fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { |
@@ -333,7 +333,7 @@ impl RootDatabase { | |||
333 | hir::db::GenericPredicatesQuery | 333 | hir::db::GenericPredicatesQuery |
334 | hir::db::GenericDefaultsQuery | 334 | hir::db::GenericDefaultsQuery |
335 | hir::db::BodyWithSourceMapQuery | 335 | hir::db::BodyWithSourceMapQuery |
336 | hir::db::BodyHirQuery | 336 | hir::db::BodyQuery |
337 | hir::db::ImplsInCrateQuery | 337 | hir::db::ImplsInCrateQuery |
338 | hir::db::ImplsForTraitQuery | 338 | hir::db::ImplsForTraitQuery |
339 | hir::db::AssociatedTyDataQuery | 339 | hir::db::AssociatedTyDataQuery |
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs index 4f9565441..99fed8689 100644 --- a/crates/ra_ide_api/src/completion/complete_postfix.rs +++ b/crates/ra_ide_api/src/completion/complete_postfix.rs | |||
@@ -13,6 +13,10 @@ use crate::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | 15 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
16 | if ctx.db.feature_flags.get("completion.enable-postfix") == false { | ||
17 | return; | ||
18 | } | ||
19 | |||
16 | let dot_receiver = match &ctx.dot_receiver { | 20 | let dot_receiver = match &ctx.dot_receiver { |
17 | Some(it) => it, | 21 | Some(it) => it, |
18 | None => return, | 22 | None => return, |
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 4e56de3f5..3e205efd1 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs | |||
@@ -598,6 +598,68 @@ mod tests { | |||
598 | } | 598 | } |
599 | 599 | ||
600 | #[test] | 600 | #[test] |
601 | fn completes_std_prelude_if_core_is_defined() { | ||
602 | assert_debug_snapshot!( | ||
603 | do_reference_completion( | ||
604 | " | ||
605 | //- /main.rs | ||
606 | fn foo() { let x: <|> } | ||
607 | |||
608 | //- /core/lib.rs | ||
609 | #[prelude_import] | ||
610 | use prelude::*; | ||
611 | |||
612 | mod prelude { | ||
613 | struct Option; | ||
614 | } | ||
615 | |||
616 | //- /std/lib.rs | ||
617 | #[prelude_import] | ||
618 | use prelude::*; | ||
619 | |||
620 | mod prelude { | ||
621 | struct String; | ||
622 | } | ||
623 | " | ||
624 | ), | ||
625 | @r###" | ||
626 | [ | ||
627 | CompletionItem { | ||
628 | label: "String", | ||
629 | source_range: [18; 18), | ||
630 | delete: [18; 18), | ||
631 | insert: "String", | ||
632 | kind: Struct, | ||
633 | }, | ||
634 | CompletionItem { | ||
635 | label: "core", | ||
636 | source_range: [18; 18), | ||
637 | delete: [18; 18), | ||
638 | insert: "core", | ||
639 | kind: Module, | ||
640 | }, | ||
641 | CompletionItem { | ||
642 | label: "foo()", | ||
643 | source_range: [18; 18), | ||
644 | delete: [18; 18), | ||
645 | insert: "foo()$0", | ||
646 | kind: Function, | ||
647 | lookup: "foo", | ||
648 | detail: "fn foo()", | ||
649 | }, | ||
650 | CompletionItem { | ||
651 | label: "std", | ||
652 | source_range: [18; 18), | ||
653 | delete: [18; 18), | ||
654 | insert: "std", | ||
655 | kind: Module, | ||
656 | }, | ||
657 | ] | ||
658 | "### | ||
659 | ); | ||
660 | } | ||
661 | |||
662 | #[test] | ||
601 | fn completes_macros_as_value() { | 663 | fn completes_macros_as_value() { |
602 | assert_debug_snapshot!( | 664 | assert_debug_snapshot!( |
603 | do_reference_completion( | 665 | do_reference_completion( |
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs index a980c56bc..30617412a 100644 --- a/crates/ra_ide_api/src/display.rs +++ b/crates/ra_ide_api/src/display.rs | |||
@@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature; | |||
15 | pub use navigation_target::NavigationTarget; | 15 | pub use navigation_target::NavigationTarget; |
16 | pub use structure::{file_structure, StructureNode}; | 16 | pub use structure::{file_structure, StructureNode}; |
17 | 17 | ||
18 | pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol}; | 18 | pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; |
19 | pub(crate) use short_label::ShortLabel; | 19 | pub(crate) use short_label::ShortLabel; |
20 | 20 | ||
21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { | 21 | pub(crate) fn function_label(node: &ast::FnDef) -> String { |
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs index 1bf81e7d5..f7ad08515 100644 --- a/crates/ra_ide_api/src/display/navigation_target.rs +++ b/crates/ra_ide_api/src/display/navigation_target.rs | |||
@@ -1,11 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{AssocItem, FieldSource, HasSource, ModuleSource}; | 3 | use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource}; |
4 | use ra_db::{FileId, SourceDatabase}; | 4 | use ra_db::{FileId, SourceDatabase}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, DocCommentsOwner}, | 6 | ast::{self, DocCommentsOwner, NameOwner}, |
7 | match_ast, AstNode, AstPtr, SmolStr, | 7 | match_ast, AstNode, SmolStr, |
8 | SyntaxKind::{self, NAME}, | 8 | SyntaxKind::{self, BIND_PAT}, |
9 | SyntaxNode, TextRange, | 9 | SyntaxNode, TextRange, |
10 | }; | 10 | }; |
11 | 11 | ||
@@ -29,19 +29,8 @@ pub struct NavigationTarget { | |||
29 | docs: Option<String>, | 29 | docs: Option<String>, |
30 | } | 30 | } |
31 | 31 | ||
32 | fn find_range_from_node( | 32 | pub(crate) trait ToNav { |
33 | db: &RootDatabase, | 33 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget; |
34 | src: hir::HirFileId, | ||
35 | node: &SyntaxNode, | ||
36 | ) -> (FileId, TextRange) { | ||
37 | let text_range = node.text_range(); | ||
38 | let (file_id, text_range) = src | ||
39 | .expansion_info(db) | ||
40 | .and_then(|expansion_info| expansion_info.find_range(text_range)) | ||
41 | .unwrap_or((src, text_range)); | ||
42 | |||
43 | // FIXME: handle recursive macro generated macro | ||
44 | (file_id.original_file(db), text_range) | ||
45 | } | 34 | } |
46 | 35 | ||
47 | impl NavigationTarget { | 36 | impl NavigationTarget { |
@@ -87,88 +76,6 @@ impl NavigationTarget { | |||
87 | self.focus_range | 76 | self.focus_range |
88 | } | 77 | } |
89 | 78 | ||
90 | pub(crate) fn from_bind_pat( | ||
91 | db: &RootDatabase, | ||
92 | file_id: FileId, | ||
93 | pat: &ast::BindPat, | ||
94 | ) -> NavigationTarget { | ||
95 | NavigationTarget::from_named(db, file_id.into(), pat, None, None) | ||
96 | } | ||
97 | |||
98 | pub(crate) fn from_symbol(db: &RootDatabase, symbol: FileSymbol) -> NavigationTarget { | ||
99 | NavigationTarget { | ||
100 | file_id: symbol.file_id, | ||
101 | name: symbol.name.clone(), | ||
102 | kind: symbol.ptr.kind(), | ||
103 | full_range: symbol.ptr.range(), | ||
104 | focus_range: symbol.name_range, | ||
105 | container_name: symbol.container_name.clone(), | ||
106 | description: description_from_symbol(db, &symbol), | ||
107 | docs: docs_from_symbol(db, &symbol), | ||
108 | } | ||
109 | } | ||
110 | |||
111 | pub(crate) fn from_pat( | ||
112 | db: &RootDatabase, | ||
113 | file_id: FileId, | ||
114 | pat: AstPtr<ast::BindPat>, | ||
115 | ) -> NavigationTarget { | ||
116 | let parse = db.parse(file_id); | ||
117 | let pat = pat.to_node(parse.tree().syntax()); | ||
118 | NavigationTarget::from_bind_pat(db, file_id, &pat) | ||
119 | } | ||
120 | |||
121 | pub(crate) fn from_self_param( | ||
122 | file_id: FileId, | ||
123 | par: AstPtr<ast::SelfParam>, | ||
124 | ) -> NavigationTarget { | ||
125 | let (name, full_range) = ("self".into(), par.syntax_node_ptr().range()); | ||
126 | |||
127 | NavigationTarget { | ||
128 | file_id, | ||
129 | name, | ||
130 | full_range, | ||
131 | focus_range: None, | ||
132 | kind: NAME, | ||
133 | container_name: None, | ||
134 | description: None, //< No document node for SelfParam | ||
135 | docs: None, //< No document node for SelfParam | ||
136 | } | ||
137 | } | ||
138 | |||
139 | pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | ||
140 | let src = module.definition_source(db); | ||
141 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | ||
142 | match src.ast { | ||
143 | ModuleSource::SourceFile(node) => { | ||
144 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | ||
145 | |||
146 | NavigationTarget::from_syntax( | ||
147 | file_id, | ||
148 | name, | ||
149 | None, | ||
150 | text_range, | ||
151 | node.syntax(), | ||
152 | None, | ||
153 | None, | ||
154 | ) | ||
155 | } | ||
156 | ModuleSource::Module(node) => { | ||
157 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | ||
158 | |||
159 | NavigationTarget::from_syntax( | ||
160 | file_id, | ||
161 | name, | ||
162 | None, | ||
163 | text_range, | ||
164 | node.syntax(), | ||
165 | node.doc_comment_text(), | ||
166 | node.short_label(), | ||
167 | ) | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 79 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
173 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 80 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
174 | if let Some(src) = module.declaration_source(db) { | 81 | if let Some(src) = module.declaration_source(db) { |
@@ -183,55 +90,7 @@ impl NavigationTarget { | |||
183 | src.ast.short_label(), | 90 | src.ast.short_label(), |
184 | ); | 91 | ); |
185 | } | 92 | } |
186 | NavigationTarget::from_module(db, module) | 93 | module.to_nav(db) |
187 | } | ||
188 | |||
189 | pub(crate) fn from_field(db: &RootDatabase, field: hir::StructField) -> NavigationTarget { | ||
190 | let src = field.source(db); | ||
191 | match src.ast { | ||
192 | FieldSource::Named(it) => NavigationTarget::from_named( | ||
193 | db, | ||
194 | src.file_id, | ||
195 | &it, | ||
196 | it.doc_comment_text(), | ||
197 | it.short_label(), | ||
198 | ), | ||
199 | FieldSource::Pos(it) => { | ||
200 | let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); | ||
201 | NavigationTarget::from_syntax( | ||
202 | file_id, | ||
203 | "".into(), | ||
204 | None, | ||
205 | text_range, | ||
206 | it.syntax(), | ||
207 | None, | ||
208 | None, | ||
209 | ) | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | pub(crate) fn from_def_source<A, D>(db: &RootDatabase, def: D) -> NavigationTarget | ||
215 | where | ||
216 | D: HasSource<Ast = A>, | ||
217 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | ||
218 | { | ||
219 | let src = def.source(db); | ||
220 | NavigationTarget::from_named( | ||
221 | db, | ||
222 | src.file_id, | ||
223 | &src.ast, | ||
224 | src.ast.doc_comment_text(), | ||
225 | src.ast.short_label(), | ||
226 | ) | ||
227 | } | ||
228 | |||
229 | pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::Adt) -> NavigationTarget { | ||
230 | match adt_def { | ||
231 | hir::Adt::Struct(it) => NavigationTarget::from_def_source(db, it), | ||
232 | hir::Adt::Union(it) => NavigationTarget::from_def_source(db, it), | ||
233 | hir::Adt::Enum(it) => NavigationTarget::from_def_source(db, it), | ||
234 | } | ||
235 | } | 94 | } |
236 | 95 | ||
237 | pub(crate) fn from_def( | 96 | pub(crate) fn from_def( |
@@ -239,14 +98,14 @@ impl NavigationTarget { | |||
239 | module_def: hir::ModuleDef, | 98 | module_def: hir::ModuleDef, |
240 | ) -> Option<NavigationTarget> { | 99 | ) -> Option<NavigationTarget> { |
241 | let nav = match module_def { | 100 | let nav = match module_def { |
242 | hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module), | 101 | hir::ModuleDef::Module(module) => module.to_nav(db), |
243 | hir::ModuleDef::Function(func) => NavigationTarget::from_def_source(db, func), | 102 | hir::ModuleDef::Function(it) => it.to_nav(db), |
244 | hir::ModuleDef::Adt(it) => NavigationTarget::from_adt_def(db, it), | 103 | hir::ModuleDef::Adt(it) => it.to_nav(db), |
245 | hir::ModuleDef::Const(it) => NavigationTarget::from_def_source(db, it), | 104 | hir::ModuleDef::Const(it) => it.to_nav(db), |
246 | hir::ModuleDef::Static(it) => NavigationTarget::from_def_source(db, it), | 105 | hir::ModuleDef::Static(it) => it.to_nav(db), |
247 | hir::ModuleDef::EnumVariant(it) => NavigationTarget::from_def_source(db, it), | 106 | hir::ModuleDef::EnumVariant(it) => it.to_nav(db), |
248 | hir::ModuleDef::Trait(it) => NavigationTarget::from_def_source(db, it), | 107 | hir::ModuleDef::Trait(it) => it.to_nav(db), |
249 | hir::ModuleDef::TypeAlias(it) => NavigationTarget::from_def_source(db, it), | 108 | hir::ModuleDef::TypeAlias(it) => it.to_nav(db), |
250 | hir::ModuleDef::BuiltinType(..) => { | 109 | hir::ModuleDef::BuiltinType(..) => { |
251 | return None; | 110 | return None; |
252 | } | 111 | } |
@@ -254,41 +113,6 @@ impl NavigationTarget { | |||
254 | Some(nav) | 113 | Some(nav) |
255 | } | 114 | } |
256 | 115 | ||
257 | pub(crate) fn from_impl_block( | ||
258 | db: &RootDatabase, | ||
259 | impl_block: hir::ImplBlock, | ||
260 | ) -> NavigationTarget { | ||
261 | let src = impl_block.source(db); | ||
262 | let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); | ||
263 | |||
264 | NavigationTarget::from_syntax( | ||
265 | file_id, | ||
266 | "impl".into(), | ||
267 | None, | ||
268 | text_range, | ||
269 | src.ast.syntax(), | ||
270 | None, | ||
271 | None, | ||
272 | ) | ||
273 | } | ||
274 | |||
275 | pub(crate) fn from_assoc_item( | ||
276 | db: &RootDatabase, | ||
277 | assoc_item: hir::AssocItem, | ||
278 | ) -> NavigationTarget { | ||
279 | match assoc_item { | ||
280 | AssocItem::Function(it) => NavigationTarget::from_def_source(db, it), | ||
281 | AssocItem::Const(it) => NavigationTarget::from_def_source(db, it), | ||
282 | AssocItem::TypeAlias(it) => NavigationTarget::from_def_source(db, it), | ||
283 | } | ||
284 | } | ||
285 | |||
286 | pub(crate) fn from_macro_def(db: &RootDatabase, macro_call: hir::MacroDef) -> NavigationTarget { | ||
287 | let src = macro_call.source(db); | ||
288 | log::debug!("nav target {:#?}", src.ast.syntax()); | ||
289 | NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None) | ||
290 | } | ||
291 | |||
292 | #[cfg(test)] | 116 | #[cfg(test)] |
293 | pub(crate) fn assert_match(&self, expected: &str) { | 117 | pub(crate) fn assert_match(&self, expected: &str) { |
294 | let actual = self.debug_render(); | 118 | let actual = self.debug_render(); |
@@ -359,6 +183,198 @@ impl NavigationTarget { | |||
359 | } | 183 | } |
360 | } | 184 | } |
361 | 185 | ||
186 | impl ToNav for FileSymbol { | ||
187 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
188 | NavigationTarget { | ||
189 | file_id: self.file_id, | ||
190 | name: self.name.clone(), | ||
191 | kind: self.ptr.kind(), | ||
192 | full_range: self.ptr.range(), | ||
193 | focus_range: self.name_range, | ||
194 | container_name: self.container_name.clone(), | ||
195 | description: description_from_symbol(db, self), | ||
196 | docs: docs_from_symbol(db, self), | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | pub(crate) trait ToNavFromAst {} | ||
202 | impl ToNavFromAst for hir::Function {} | ||
203 | impl ToNavFromAst for hir::Const {} | ||
204 | impl ToNavFromAst for hir::Static {} | ||
205 | impl ToNavFromAst for hir::Struct {} | ||
206 | impl ToNavFromAst for hir::Enum {} | ||
207 | impl ToNavFromAst for hir::EnumVariant {} | ||
208 | impl ToNavFromAst for hir::Union {} | ||
209 | impl ToNavFromAst for hir::TypeAlias {} | ||
210 | impl ToNavFromAst for hir::Trait {} | ||
211 | |||
212 | impl<D> ToNav for D | ||
213 | where | ||
214 | D: HasSource + ToNavFromAst + Copy, | ||
215 | D::Ast: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | ||
216 | { | ||
217 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
218 | let src = self.source(db); | ||
219 | NavigationTarget::from_named( | ||
220 | db, | ||
221 | src.file_id, | ||
222 | &src.ast, | ||
223 | src.ast.doc_comment_text(), | ||
224 | src.ast.short_label(), | ||
225 | ) | ||
226 | } | ||
227 | } | ||
228 | |||
229 | impl ToNav for hir::Module { | ||
230 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
231 | let src = self.definition_source(db); | ||
232 | let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | ||
233 | match src.ast { | ||
234 | ModuleSource::SourceFile(node) => { | ||
235 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | ||
236 | |||
237 | NavigationTarget::from_syntax( | ||
238 | file_id, | ||
239 | name, | ||
240 | None, | ||
241 | text_range, | ||
242 | node.syntax(), | ||
243 | None, | ||
244 | None, | ||
245 | ) | ||
246 | } | ||
247 | ModuleSource::Module(node) => { | ||
248 | let (file_id, text_range) = find_range_from_node(db, src.file_id, node.syntax()); | ||
249 | |||
250 | NavigationTarget::from_syntax( | ||
251 | file_id, | ||
252 | name, | ||
253 | None, | ||
254 | text_range, | ||
255 | node.syntax(), | ||
256 | node.doc_comment_text(), | ||
257 | node.short_label(), | ||
258 | ) | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | } | ||
263 | |||
264 | impl ToNav for hir::ImplBlock { | ||
265 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
266 | let src = self.source(db); | ||
267 | let (file_id, text_range) = find_range_from_node(db, src.file_id, src.ast.syntax()); | ||
268 | |||
269 | NavigationTarget::from_syntax( | ||
270 | file_id, | ||
271 | "impl".into(), | ||
272 | None, | ||
273 | text_range, | ||
274 | src.ast.syntax(), | ||
275 | None, | ||
276 | None, | ||
277 | ) | ||
278 | } | ||
279 | } | ||
280 | |||
281 | impl ToNav for hir::StructField { | ||
282 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
283 | let src = self.source(db); | ||
284 | |||
285 | match src.ast { | ||
286 | FieldSource::Named(it) => NavigationTarget::from_named( | ||
287 | db, | ||
288 | src.file_id, | ||
289 | &it, | ||
290 | it.doc_comment_text(), | ||
291 | it.short_label(), | ||
292 | ), | ||
293 | FieldSource::Pos(it) => { | ||
294 | let (file_id, text_range) = find_range_from_node(db, src.file_id, it.syntax()); | ||
295 | NavigationTarget::from_syntax( | ||
296 | file_id, | ||
297 | "".into(), | ||
298 | None, | ||
299 | text_range, | ||
300 | it.syntax(), | ||
301 | None, | ||
302 | None, | ||
303 | ) | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | |||
309 | impl ToNav for hir::MacroDef { | ||
310 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
311 | let src = self.source(db); | ||
312 | log::debug!("nav target {:#?}", src.ast.syntax()); | ||
313 | NavigationTarget::from_named(db, src.file_id, &src.ast, src.ast.doc_comment_text(), None) | ||
314 | } | ||
315 | } | ||
316 | |||
317 | impl ToNav for hir::Adt { | ||
318 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
319 | match self { | ||
320 | hir::Adt::Struct(it) => it.to_nav(db), | ||
321 | hir::Adt::Union(it) => it.to_nav(db), | ||
322 | hir::Adt::Enum(it) => it.to_nav(db), | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | |||
327 | impl ToNav for hir::AssocItem { | ||
328 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
329 | match self { | ||
330 | AssocItem::Function(it) => it.to_nav(db), | ||
331 | AssocItem::Const(it) => it.to_nav(db), | ||
332 | AssocItem::TypeAlias(it) => it.to_nav(db), | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | |||
337 | impl ToNav for hir::Local { | ||
338 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | ||
339 | let src = self.source(db); | ||
340 | let (full_range, focus_range) = match src.ast { | ||
341 | Either::A(it) => { | ||
342 | (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range())) | ||
343 | } | ||
344 | Either::B(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())), | ||
345 | }; | ||
346 | let name = match self.name(db) { | ||
347 | Some(it) => it.to_string().into(), | ||
348 | None => "".into(), | ||
349 | }; | ||
350 | NavigationTarget { | ||
351 | file_id: src.file_id.original_file(db), | ||
352 | name, | ||
353 | kind: BIND_PAT, | ||
354 | full_range, | ||
355 | focus_range, | ||
356 | container_name: None, | ||
357 | description: None, | ||
358 | docs: None, | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | |||
363 | fn find_range_from_node( | ||
364 | db: &RootDatabase, | ||
365 | src: hir::HirFileId, | ||
366 | node: &SyntaxNode, | ||
367 | ) -> (FileId, TextRange) { | ||
368 | let text_range = node.text_range(); | ||
369 | let (file_id, text_range) = src | ||
370 | .expansion_info(db) | ||
371 | .and_then(|expansion_info| expansion_info.find_range(text_range)) | ||
372 | .unwrap_or((src, text_range)); | ||
373 | |||
374 | // FIXME: handle recursive macro generated macro | ||
375 | (file_id.original_file(db), text_range) | ||
376 | } | ||
377 | |||
362 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { | 378 | pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { |
363 | let parse = db.parse(symbol.file_id); | 379 | let parse = db.parse(symbol.file_id); |
364 | let node = symbol.ptr.to_node(parse.tree().syntax()); | 380 | let node = symbol.ptr.to_node(parse.tree().syntax()); |
diff --git a/crates/ra_ide_api/src/feature_flags.rs b/crates/ra_ide_api/src/feature_flags.rs index d3ca7be03..de4ae513d 100644 --- a/crates/ra_ide_api/src/feature_flags.rs +++ b/crates/ra_ide_api/src/feature_flags.rs | |||
@@ -54,6 +54,7 @@ impl Default for FeatureFlags { | |||
54 | FeatureFlags::new(&[ | 54 | FeatureFlags::new(&[ |
55 | ("lsp.diagnostics", true), | 55 | ("lsp.diagnostics", true), |
56 | ("completion.insertion.add-call-parenthesis", true), | 56 | ("completion.insertion.add-call-parenthesis", true), |
57 | ("completion.enable-postfix", true), | ||
57 | ("notifications.workspace-loaded", true), | 58 | ("notifications.workspace-loaded", true), |
58 | ]) | 59 | ]) |
59 | } | 60 | } |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index afa59cbe3..6c8387f6c 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::RootDatabase, | 11 | db::RootDatabase, |
12 | display::ShortLabel, | 12 | display::{ShortLabel, ToNav}, |
13 | references::{classify_name_ref, NameKind::*}, | 13 | references::{classify_name_ref, NameKind::*}, |
14 | FilePosition, NavigationTarget, RangeInfo, | 14 | FilePosition, NavigationTarget, RangeInfo, |
15 | }; | 15 | }; |
@@ -56,20 +56,19 @@ pub(crate) fn reference_definition( | |||
56 | 56 | ||
57 | let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); | 57 | let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); |
58 | match name_kind { | 58 | match name_kind { |
59 | Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), | 59 | Some(Macro(mac)) => return Exact(mac.to_nav(db)), |
60 | Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)), | 60 | Some(Field(field)) => return Exact(field.to_nav(db)), |
61 | Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), | 61 | Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)), |
62 | Some(Def(def)) => match NavigationTarget::from_def(db, def) { | 62 | Some(Def(def)) => match NavigationTarget::from_def(db, def) { |
63 | Some(nav) => return Exact(nav), | 63 | Some(nav) => return Exact(nav), |
64 | None => return Approximate(vec![]), | 64 | None => return Approximate(vec![]), |
65 | }, | 65 | }, |
66 | Some(SelfType(ty)) => { | 66 | Some(SelfType(ty)) => { |
67 | if let Some((def_id, _)) = ty.as_adt() { | 67 | if let Some((adt, _)) = ty.as_adt() { |
68 | return Exact(NavigationTarget::from_adt_def(db, def_id)); | 68 | return Exact(adt.to_nav(db)); |
69 | } | 69 | } |
70 | } | 70 | } |
71 | Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), | 71 | Some(Local(local)) => return Exact(local.to_nav(db)), |
72 | Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)), | ||
73 | Some(GenericParam(_)) => { | 72 | Some(GenericParam(_)) => { |
74 | // FIXME: go to the generic param def | 73 | // FIXME: go to the generic param def |
75 | } | 74 | } |
@@ -79,7 +78,7 @@ pub(crate) fn reference_definition( | |||
79 | // Fallback index based approach: | 78 | // Fallback index based approach: |
80 | let navs = crate::symbol_index::index_resolve(db, name_ref) | 79 | let navs = crate::symbol_index::index_resolve(db, name_ref) |
81 | .into_iter() | 80 | .into_iter() |
82 | .map(|s| NavigationTarget::from_symbol(db, s)) | 81 | .map(|s| s.to_nav(db)) |
83 | .collect(); | 82 | .collect(); |
84 | Approximate(navs) | 83 | Approximate(navs) |
85 | } | 84 | } |
@@ -95,7 +94,7 @@ pub(crate) fn name_definition( | |||
95 | if module.has_semi() { | 94 | if module.has_semi() { |
96 | let src = hir::Source { file_id: file_id.into(), ast: module }; | 95 | let src = hir::Source { file_id: file_id.into(), ast: module }; |
97 | if let Some(child_module) = hir::Module::from_declaration(db, src) { | 96 | if let Some(child_module) = hir::Module::from_declaration(db, src) { |
98 | let nav = NavigationTarget::from_module(db, child_module); | 97 | let nav = child_module.to_nav(db); |
99 | return Some(vec![nav]); | 98 | return Some(vec![nav]); |
100 | } | 99 | } |
101 | } | 100 | } |
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs index 059d80524..71146591d 100644 --- a/crates/ra_ide_api/src/goto_type_definition.rs +++ b/crates/ra_ide_api/src/goto_type_definition.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use ra_db::SourceDatabase; | 3 | use ra_db::SourceDatabase; |
4 | use ra_syntax::{ast, AstNode}; | 4 | use ra_syntax::{ast, AstNode}; |
5 | 5 | ||
6 | use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo}; | 6 | use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo}; |
7 | 7 | ||
8 | pub(crate) fn goto_type_definition( | 8 | pub(crate) fn goto_type_definition( |
9 | db: &RootDatabase, | 9 | db: &RootDatabase, |
@@ -33,7 +33,7 @@ pub(crate) fn goto_type_definition( | |||
33 | 33 | ||
34 | let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; | 34 | let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; |
35 | 35 | ||
36 | let nav = NavigationTarget::from_adt_def(db, adt_def); | 36 | let nav = adt_def.to_nav(db); |
37 | Some(RangeInfo::new(node.text_range(), vec![nav])) | 37 | Some(RangeInfo::new(node.text_range(), vec![nav])) |
38 | } | 38 | } |
39 | 39 | ||
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index ba328efa1..07d511fb3 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs | |||
@@ -5,7 +5,7 @@ use ra_db::SourceDatabase; | |||
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, | 6 | algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, |
7 | ast::{self, DocCommentsOwner}, | 7 | ast::{self, DocCommentsOwner}, |
8 | match_ast, AstNode, | 8 | AstNode, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, | 14 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, |
15 | rust_code_markup_with_doc, ShortLabel, | 15 | rust_code_markup_with_doc, ShortLabel, |
16 | }, | 16 | }, |
17 | references::{classify_name_ref, NameKind::*}, | 17 | references::{classify_name, classify_name_ref, NameKind, NameKind::*}, |
18 | FilePosition, FileRange, RangeInfo, | 18 | FilePosition, FileRange, RangeInfo, |
19 | }; | 19 | }; |
20 | 20 | ||
@@ -92,69 +92,88 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> { | |||
92 | } | 92 | } |
93 | } | 93 | } |
94 | 94 | ||
95 | fn hover_text_from_name_kind( | ||
96 | db: &RootDatabase, | ||
97 | name_kind: NameKind, | ||
98 | no_fallback: &mut bool, | ||
99 | ) -> Option<String> { | ||
100 | return match name_kind { | ||
101 | Macro(it) => { | ||
102 | let src = it.source(db); | ||
103 | hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast))) | ||
104 | } | ||
105 | Field(it) => { | ||
106 | let src = it.source(db); | ||
107 | match src.ast { | ||
108 | hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()), | ||
109 | _ => None, | ||
110 | } | ||
111 | } | ||
112 | AssocItem(it) => match it { | ||
113 | hir::AssocItem::Function(it) => from_def_source(db, it), | ||
114 | hir::AssocItem::Const(it) => from_def_source(db, it), | ||
115 | hir::AssocItem::TypeAlias(it) => from_def_source(db, it), | ||
116 | }, | ||
117 | Def(it) => match it { | ||
118 | hir::ModuleDef::Module(it) => match it.definition_source(db).ast { | ||
119 | hir::ModuleSource::Module(it) => { | ||
120 | hover_text(it.doc_comment_text(), it.short_label()) | ||
121 | } | ||
122 | _ => None, | ||
123 | }, | ||
124 | hir::ModuleDef::Function(it) => from_def_source(db, it), | ||
125 | hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it), | ||
126 | hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it), | ||
127 | hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it), | ||
128 | hir::ModuleDef::EnumVariant(it) => from_def_source(db, it), | ||
129 | hir::ModuleDef::Const(it) => from_def_source(db, it), | ||
130 | hir::ModuleDef::Static(it) => from_def_source(db, it), | ||
131 | hir::ModuleDef::Trait(it) => from_def_source(db, it), | ||
132 | hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), | ||
133 | hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), | ||
134 | }, | ||
135 | SelfType(ty) => match ty.as_adt() { | ||
136 | Some((adt_def, _)) => match adt_def { | ||
137 | hir::Adt::Struct(it) => from_def_source(db, it), | ||
138 | hir::Adt::Union(it) => from_def_source(db, it), | ||
139 | hir::Adt::Enum(it) => from_def_source(db, it), | ||
140 | }, | ||
141 | _ => None, | ||
142 | }, | ||
143 | Local(_) => { | ||
144 | // Hover for these shows type names | ||
145 | *no_fallback = true; | ||
146 | None | ||
147 | } | ||
148 | GenericParam(_) => { | ||
149 | // FIXME: Hover for generic param | ||
150 | None | ||
151 | } | ||
152 | }; | ||
153 | |||
154 | fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String> | ||
155 | where | ||
156 | D: HasSource<Ast = A>, | ||
157 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | ||
158 | { | ||
159 | let src = def.source(db); | ||
160 | hover_text(src.ast.doc_comment_text(), src.ast.short_label()) | ||
161 | } | ||
162 | } | ||
163 | |||
95 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { | 164 | pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { |
96 | let parse = db.parse(position.file_id); | 165 | let parse = db.parse(position.file_id); |
97 | let file = parse.tree(); | 166 | let file = parse.tree(); |
167 | |||
98 | let mut res = HoverResult::new(); | 168 | let mut res = HoverResult::new(); |
99 | 169 | ||
100 | let mut range = None; | 170 | let mut range = if let Some(name_ref) = |
101 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { | 171 | find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) |
172 | { | ||
102 | let mut no_fallback = false; | 173 | let mut no_fallback = false; |
103 | let name_kind = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind); | 174 | if let Some(name_kind) = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind) |
104 | match name_kind { | 175 | { |
105 | Some(Macro(it)) => { | 176 | res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback)) |
106 | let src = it.source(db); | ||
107 | res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast)))); | ||
108 | } | ||
109 | Some(Field(it)) => { | ||
110 | let src = it.source(db); | ||
111 | if let hir::FieldSource::Named(it) = src.ast { | ||
112 | res.extend(hover_text(it.doc_comment_text(), it.short_label())); | ||
113 | } | ||
114 | } | ||
115 | Some(AssocItem(it)) => res.extend(match it { | ||
116 | hir::AssocItem::Function(it) => from_def_source(db, it), | ||
117 | hir::AssocItem::Const(it) => from_def_source(db, it), | ||
118 | hir::AssocItem::TypeAlias(it) => from_def_source(db, it), | ||
119 | }), | ||
120 | Some(Def(it)) => { | ||
121 | match it { | ||
122 | hir::ModuleDef::Module(it) => { | ||
123 | if let hir::ModuleSource::Module(it) = it.definition_source(db).ast { | ||
124 | res.extend(hover_text(it.doc_comment_text(), it.short_label())) | ||
125 | } | ||
126 | } | ||
127 | hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)), | ||
128 | hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)), | ||
129 | hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)), | ||
130 | hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)), | ||
131 | hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)), | ||
132 | hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)), | ||
133 | hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)), | ||
134 | hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)), | ||
135 | hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)), | ||
136 | hir::ModuleDef::BuiltinType(_) => { | ||
137 | // FIXME: hover for builtin Type ? | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | Some(SelfType(ty)) => { | ||
142 | if let Some((adt_def, _)) = ty.as_adt() { | ||
143 | res.extend(match adt_def { | ||
144 | hir::Adt::Struct(it) => from_def_source(db, it), | ||
145 | hir::Adt::Union(it) => from_def_source(db, it), | ||
146 | hir::Adt::Enum(it) => from_def_source(db, it), | ||
147 | }) | ||
148 | } | ||
149 | } | ||
150 | Some(Pat(_)) | Some(SelfParam(_)) => { | ||
151 | // Hover for these shows type names | ||
152 | no_fallback = true; | ||
153 | } | ||
154 | Some(GenericParam(_)) => { | ||
155 | // FIXME: Hover for generic param | ||
156 | } | ||
157 | None => {} | ||
158 | } | 177 | } |
159 | 178 | ||
160 | if res.is_empty() && !no_fallback { | 179 | if res.is_empty() && !no_fallback { |
@@ -168,55 +187,24 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
168 | } | 187 | } |
169 | 188 | ||
170 | if !res.is_empty() { | 189 | if !res.is_empty() { |
171 | range = Some(name_ref.syntax().text_range()) | 190 | Some(name_ref.syntax().text_range()) |
191 | } else { | ||
192 | None | ||
172 | } | 193 | } |
173 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { | 194 | } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { |
174 | if let Some(parent) = name.syntax().parent() { | 195 | if let Some(name_kind) = classify_name(db, position.file_id, &name).map(|d| d.kind) { |
175 | let text = match_ast! { | 196 | let mut _b: bool = true; |
176 | match parent { | 197 | res.extend(hover_text_from_name_kind(db, name_kind, &mut _b)); |
177 | ast::StructDef(it) => { | ||
178 | hover_text(it.doc_comment_text(), it.short_label()) | ||
179 | }, | ||
180 | ast::EnumDef(it) => { | ||
181 | hover_text(it.doc_comment_text(), it.short_label()) | ||
182 | }, | ||
183 | ast::EnumVariant(it) => { | ||
184 | hover_text(it.doc_comment_text(), it.short_label()) | ||
185 | }, | ||
186 | ast::FnDef(it) => { | ||
187 | hover_text(it.doc_comment_text(), it.short_label()) | ||
188 | }, | ||
189 | ast::TypeAliasDef(it) => { | ||
190 | hover_text(it.doc_comment_text(), it.short_label()) | ||
191 | }, | ||
192 | ast::ConstDef(it) => { | ||
193 | hover_text(it.doc_comment_text(), it.short_label()) | ||
194 | }, | ||
195 | ast::StaticDef(it) => { | ||
196 | hover_text(it.doc_comment_text(), it.short_label()) | ||
197 | }, | ||
198 | ast::TraitDef(it) => { | ||
199 | hover_text(it.doc_comment_text(), it.short_label()) | ||
200 | }, | ||
201 | ast::RecordFieldDef(it) => { | ||
202 | hover_text(it.doc_comment_text(), it.short_label()) | ||
203 | }, | ||
204 | ast::Module(it) => { | ||
205 | hover_text(it.doc_comment_text(), it.short_label()) | ||
206 | }, | ||
207 | ast::MacroCall(it) => { | ||
208 | hover_text(it.doc_comment_text(), None) | ||
209 | }, | ||
210 | _ => None, | ||
211 | } | ||
212 | }; | ||
213 | res.extend(text); | ||
214 | } | 198 | } |
215 | 199 | ||
216 | if !res.is_empty() && range.is_none() { | 200 | if !res.is_empty() { |
217 | range = Some(name.syntax().text_range()); | 201 | Some(name.syntax().text_range()) |
202 | } else { | ||
203 | None | ||
218 | } | 204 | } |
219 | } | 205 | } else { |
206 | None | ||
207 | }; | ||
220 | 208 | ||
221 | if range.is_none() { | 209 | if range.is_none() { |
222 | let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| { | 210 | let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| { |
@@ -225,23 +213,13 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
225 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; | 213 | let frange = FileRange { file_id: position.file_id, range: node.text_range() }; |
226 | res.extend(type_of(db, frange).map(rust_code_markup)); | 214 | res.extend(type_of(db, frange).map(rust_code_markup)); |
227 | range = Some(node.text_range()); | 215 | range = Some(node.text_range()); |
228 | } | 216 | }; |
229 | 217 | ||
230 | let range = range?; | 218 | let range = range?; |
231 | if res.is_empty() { | 219 | if res.is_empty() { |
232 | return None; | 220 | return None; |
233 | } | 221 | } |
234 | let res = RangeInfo::new(range, res); | 222 | Some(RangeInfo::new(range, res)) |
235 | return Some(res); | ||
236 | |||
237 | fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String> | ||
238 | where | ||
239 | D: HasSource<Ast = A>, | ||
240 | A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel, | ||
241 | { | ||
242 | let src = def.source(db); | ||
243 | hover_text(src.ast.doc_comment_text(), src.ast.short_label()) | ||
244 | } | ||
245 | } | 223 | } |
246 | 224 | ||
247 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { | 225 | pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { |
@@ -722,4 +700,16 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
722 | assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); | 700 | assert_eq!(trim_markup_opt(hover.info.first()), Some("macro_rules! foo")); |
723 | assert_eq!(hover.info.is_exact(), true); | 701 | assert_eq!(hover.info.is_exact(), true); |
724 | } | 702 | } |
703 | |||
704 | #[test] | ||
705 | fn test_hover_tuple_field() { | ||
706 | let (analysis, position) = single_file_with_position( | ||
707 | " | ||
708 | struct TS(String, i32<|>); | ||
709 | ", | ||
710 | ); | ||
711 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
712 | assert_eq!(trim_markup_opt(hover.info.first()), Some("i32")); | ||
713 | assert_eq!(hover.info.is_exact(), true); | ||
714 | } | ||
725 | } | 715 | } |
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs index b899ed3a5..bc9b66550 100644 --- a/crates/ra_ide_api/src/impls.rs +++ b/crates/ra_ide_api/src/impls.rs | |||
@@ -4,7 +4,7 @@ use hir::{db::HirDatabase, ApplicationTy, FromSource, Ty, TypeCtor}; | |||
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 5 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
6 | 6 | ||
7 | use crate::{db::RootDatabase, FilePosition, NavigationTarget, RangeInfo}; | 7 | use crate::{db::RootDatabase, display::ToNav, FilePosition, NavigationTarget, RangeInfo}; |
8 | 8 | ||
9 | pub(crate) fn goto_implementation( | 9 | pub(crate) fn goto_implementation( |
10 | db: &RootDatabase, | 10 | db: &RootDatabase, |
@@ -58,7 +58,7 @@ fn impls_for_def( | |||
58 | impls | 58 | impls |
59 | .all_impls() | 59 | .all_impls() |
60 | .filter(|impl_block| is_equal_for_find_impls(&ty, &impl_block.target_ty(db))) | 60 | .filter(|impl_block| is_equal_for_find_impls(&ty, &impl_block.target_ty(db))) |
61 | .map(|imp| NavigationTarget::from_impl_block(db, imp)) | 61 | .map(|imp| imp.to_nav(db)) |
62 | .collect(), | 62 | .collect(), |
63 | ) | 63 | ) |
64 | } | 64 | } |
@@ -75,12 +75,7 @@ fn impls_for_trait( | |||
75 | let krate = module.krate(); | 75 | let krate = module.krate(); |
76 | let impls = db.impls_in_crate(krate); | 76 | let impls = db.impls_in_crate(krate); |
77 | 77 | ||
78 | Some( | 78 | Some(impls.lookup_impl_blocks_for_trait(tr).map(|imp| imp.to_nav(db)).collect()) |
79 | impls | ||
80 | .lookup_impl_blocks_for_trait(tr) | ||
81 | .map(|imp| NavigationTarget::from_impl_block(db, imp)) | ||
82 | .collect(), | ||
83 | ) | ||
84 | } | 79 | } |
85 | 80 | ||
86 | fn is_equal_for_find_impls(original_ty: &Ty, impl_ty: &Ty) -> bool { | 81 | fn is_equal_for_find_impls(original_ty: &Ty, impl_ty: &Ty) -> bool { |
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index d0188da44..484fbcc82 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -56,7 +56,7 @@ use ra_db::{ | |||
56 | }; | 56 | }; |
57 | use ra_syntax::{SourceFile, TextRange, TextUnit}; | 57 | use ra_syntax::{SourceFile, TextRange, TextUnit}; |
58 | 58 | ||
59 | use crate::{db::LineIndexDatabase, symbol_index::FileSymbol}; | 59 | use crate::{db::LineIndexDatabase, display::ToNav, symbol_index::FileSymbol}; |
60 | 60 | ||
61 | pub use crate::{ | 61 | pub use crate::{ |
62 | assists::{Assist, AssistId}, | 62 | assists::{Assist, AssistId}, |
@@ -351,7 +351,7 @@ impl Analysis { | |||
351 | self.with_db(|db| { | 351 | self.with_db(|db| { |
352 | symbol_index::world_symbols(db, query) | 352 | symbol_index::world_symbols(db, query) |
353 | .into_iter() | 353 | .into_iter() |
354 | .map(|s| NavigationTarget::from_symbol(db, s)) | 354 | .map(|s| s.to_nav(db)) |
355 | .collect::<Vec<_>>() | 355 | .collect::<Vec<_>>() |
356 | }) | 356 | }) |
357 | } | 357 | } |
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index b5b1c9a16..9cb9433e7 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs | |||
@@ -19,7 +19,9 @@ use ra_db::{SourceDatabase, SourceDatabaseExt}; | |||
19 | use ra_prof::profile; | 19 | use ra_prof::profile; |
20 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; | 20 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; |
21 | 21 | ||
22 | use crate::{db::RootDatabase, FilePosition, FileRange, NavigationTarget, RangeInfo}; | 22 | use crate::{ |
23 | db::RootDatabase, display::ToNav, FilePosition, FileRange, NavigationTarget, RangeInfo, | ||
24 | }; | ||
23 | 25 | ||
24 | pub(crate) use self::{ | 26 | pub(crate) use self::{ |
25 | classify::{classify_name, classify_name_ref}, | 27 | classify::{classify_name, classify_name_ref}, |
@@ -76,16 +78,15 @@ pub(crate) fn find_all_refs( | |||
76 | let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; | 78 | let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; |
77 | 79 | ||
78 | let declaration = match def.kind { | 80 | let declaration = match def.kind { |
79 | NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac), | 81 | NameKind::Macro(mac) => mac.to_nav(db), |
80 | NameKind::Field(field) => NavigationTarget::from_field(db, field), | 82 | NameKind::Field(field) => field.to_nav(db), |
81 | NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), | 83 | NameKind::AssocItem(assoc) => assoc.to_nav(db), |
82 | NameKind::Def(def) => NavigationTarget::from_def(db, def)?, | 84 | NameKind::Def(def) => NavigationTarget::from_def(db, def)?, |
83 | NameKind::SelfType(ref ty) => match ty.as_adt() { | 85 | NameKind::SelfType(ref ty) => match ty.as_adt() { |
84 | Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), | 86 | Some((adt, _)) => adt.to_nav(db), |
85 | None => return None, | 87 | None => return None, |
86 | }, | 88 | }, |
87 | NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), | 89 | NameKind::Local(local) => local.to_nav(db), |
88 | NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par), | ||
89 | NameKind::GenericParam(_) => return None, | 90 | NameKind::GenericParam(_) => return None, |
90 | }; | 91 | }; |
91 | 92 | ||
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 153082d5b..217f9951e 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | //! Functions that are used to classify an element from its definition or reference. | 1 | //! Functions that are used to classify an element from its definition or reference. |
2 | 2 | ||
3 | use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; | 3 | use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; |
4 | use ra_db::FileId; | 4 | use ra_db::FileId; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ast, match_ast, AstNode, AstPtr}; | 6 | use ra_syntax::{ast, match_ast, AstNode}; |
7 | use test_utils::tested_by; | 7 | use test_utils::tested_by; |
8 | 8 | ||
9 | use super::{ | 9 | use super::{ |
10 | name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field}, | 10 | name_definition::{from_assoc_item, from_module_def, from_struct_field}, |
11 | NameDefinition, NameKind, | 11 | NameDefinition, NameKind, |
12 | }; | 12 | }; |
13 | use crate::db::RootDatabase; | 13 | use crate::db::RootDatabase; |
@@ -25,7 +25,13 @@ pub(crate) fn classify_name( | |||
25 | match_ast! { | 25 | match_ast! { |
26 | match parent { | 26 | match parent { |
27 | ast::BindPat(it) => { | 27 | ast::BindPat(it) => { |
28 | from_pat(db, file_id, AstPtr::new(&it)) | 28 | let src = hir::Source { file_id, ast: it }; |
29 | let local = hir::Local::from_source(db, src)?; | ||
30 | Some(NameDefinition { | ||
31 | visibility: None, | ||
32 | container: local.module(db), | ||
33 | kind: NameKind::Local(local), | ||
34 | }) | ||
29 | }, | 35 | }, |
30 | ast::RecordFieldDef(it) => { | 36 | ast::RecordFieldDef(it) => { |
31 | let ast = hir::FieldSource::Named(it); | 37 | let ast = hir::FieldSource::Named(it); |
@@ -159,10 +165,10 @@ pub(crate) fn classify_name_ref( | |||
159 | match resolved { | 165 | match resolved { |
160 | Def(def) => Some(from_module_def(db, def, Some(container))), | 166 | Def(def) => Some(from_module_def(db, def, Some(container))), |
161 | AssocItem(item) => Some(from_assoc_item(db, item)), | 167 | AssocItem(item) => Some(from_assoc_item(db, item)), |
162 | LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), | 168 | Local(local) => { |
163 | LocalBinding(Either::B(par)) => { | 169 | let container = local.module(db); |
164 | let kind = NameKind::SelfParam(par); | 170 | let kind = NameKind::Local(local); |
165 | Some(NameDefinition { kind, container, visibility }) | 171 | Some(NameDefinition { kind, container, visibility: None }) |
166 | } | 172 | } |
167 | GenericParam(par) => { | 173 | GenericParam(par) => { |
168 | // FIXME: get generic param def | 174 | // FIXME: get generic param def |
diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs index 4580bc789..ccd75278a 100644 --- a/crates/ra_ide_api/src/references/name_definition.rs +++ b/crates/ra_ide_api/src/references/name_definition.rs | |||
@@ -4,10 +4,10 @@ | |||
4 | //! Note that the reference search is possible for not all of the classified items. | 4 | //! Note that the reference search is possible for not all of the classified items. |
5 | 5 | ||
6 | use hir::{ | 6 | use hir::{ |
7 | db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, | 7 | Adt, AssocItem, GenericParam, HasSource, Local, MacroDef, Module, ModuleDef, StructField, Ty, |
8 | Module, ModuleDef, StructField, Ty, VariantDef, | 8 | VariantDef, |
9 | }; | 9 | }; |
10 | use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; | 10 | use ra_syntax::{ast, ast::VisibilityOwner}; |
11 | 11 | ||
12 | use crate::db::RootDatabase; | 12 | use crate::db::RootDatabase; |
13 | 13 | ||
@@ -18,9 +18,8 @@ pub enum NameKind { | |||
18 | AssocItem(AssocItem), | 18 | AssocItem(AssocItem), |
19 | Def(ModuleDef), | 19 | Def(ModuleDef), |
20 | SelfType(Ty), | 20 | SelfType(Ty), |
21 | Pat((DefWithBody, AstPtr<ast::BindPat>)), | 21 | Local(Local), |
22 | SelfParam(AstPtr<ast::SelfParam>), | 22 | GenericParam(GenericParam), |
23 | GenericParam(u32), | ||
24 | } | 23 | } |
25 | 24 | ||
26 | #[derive(PartialEq, Eq)] | 25 | #[derive(PartialEq, Eq)] |
@@ -30,36 +29,6 @@ pub(crate) struct NameDefinition { | |||
30 | pub kind: NameKind, | 29 | pub kind: NameKind, |
31 | } | 30 | } |
32 | 31 | ||
33 | pub(super) fn from_pat( | ||
34 | db: &RootDatabase, | ||
35 | file_id: HirFileId, | ||
36 | pat: AstPtr<ast::BindPat>, | ||
37 | ) -> Option<NameDefinition> { | ||
38 | let root = db.parse_or_expand(file_id)?; | ||
39 | let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { | ||
40 | match_ast! { | ||
41 | match node { | ||
42 | ast::FnDef(it) => { | ||
43 | let src = hir::Source { file_id, ast: it }; | ||
44 | Some(hir::Function::from_source(db, src)?.into()) | ||
45 | }, | ||
46 | ast::ConstDef(it) => { | ||
47 | let src = hir::Source { file_id, ast: it }; | ||
48 | Some(hir::Const::from_source(db, src)?.into()) | ||
49 | }, | ||
50 | ast::StaticDef(it) => { | ||
51 | let src = hir::Source { file_id, ast: it }; | ||
52 | Some(hir::Static::from_source(db, src)?.into()) | ||
53 | }, | ||
54 | _ => None, | ||
55 | } | ||
56 | } | ||
57 | })?; | ||
58 | let kind = NameKind::Pat((def, pat)); | ||
59 | let container = def.module(db); | ||
60 | Some(NameDefinition { kind, container, visibility: None }) | ||
61 | } | ||
62 | |||
63 | pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { | 32 | pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { |
64 | let container = item.module(db); | 33 | let container = item.module(db); |
65 | let visibility = match item { | 34 | let visibility = match item { |
diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index f2789e0b2..2907787c2 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs | |||
@@ -71,13 +71,13 @@ impl NameDefinition { | |||
71 | let module_src = self.container.definition_source(db); | 71 | let module_src = self.container.definition_source(db); |
72 | let file_id = module_src.file_id.original_file(db); | 72 | let file_id = module_src.file_id.original_file(db); |
73 | 73 | ||
74 | if let NameKind::Pat((def, _)) = self.kind { | 74 | if let NameKind::Local(var) = self.kind { |
75 | let mut res = FxHashMap::default(); | 75 | let range = match var.parent(db) { |
76 | let range = match def { | ||
77 | DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), | 76 | DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), |
78 | DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), | 77 | DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), |
79 | DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), | 78 | DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), |
80 | }; | 79 | }; |
80 | let mut res = FxHashMap::default(); | ||
81 | res.insert(file_id, Some(range)); | 81 | res.insert(file_id, Some(range)); |
82 | return SearchScope::new(res); | 82 | return SearchScope::new(res); |
83 | } | 83 | } |
diff --git a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html index ed664817e..79f11ea80 100644 --- a/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html +++ b/crates/ra_ide_api/src/snapshots/rainbow_highlighting.html | |||
@@ -20,14 +20,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
20 | .keyword\.control { color: #F0DFAF; font-weight: bold; } | 20 | .keyword\.control { color: #F0DFAF; font-weight: bold; } |
21 | </style> | 21 | </style> |
22 | <pre><code><span class="keyword">fn</span> <span class="function">main</span>() { | 22 | <pre><code><span class="keyword">fn</span> <span class="function">main</span>() { |
23 | <span class="keyword">let</span> <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>; | 23 | <span class="keyword">let</span> <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>; |
24 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5695551762718493399" style="color: hsl(272,48%,45%);">x</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>(); | 24 | <span class="keyword">let</span> <span class="variable" data-binding-hash="14702933417323009544" style="color: hsl(108,90%,49%);">x</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>(); |
25 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5435401749617022797" style="color: hsl(353,77%,74%);">y</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>(); | 25 | <span class="keyword">let</span> <span class="variable" data-binding-hash="5443150872754369068" style="color: hsl(215,43%,43%);">y</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>(); |
26 | 26 | ||
27 | <span class="keyword">let</span> <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span> = <span class="string">"other color please!"</span>; | 27 | <span class="keyword">let</span> <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span> = <span class="string">"other color please!"</span>; |
28 | <span class="keyword">let</span> <span class="variable" data-binding-hash="14878783531007968800" style="color: hsl(265,73%,83%);">y</span> = <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span>.<span class="text">to_string</span>(); | 28 | <span class="keyword">let</span> <span class="variable" data-binding-hash="2073121142529774969" style="color: hsl(320,43%,74%);">y</span> = <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span>.<span class="text">to_string</span>(); |
29 | } | 29 | } |
30 | 30 | ||
31 | <span class="keyword">fn</span> <span class="function">bar</span>() { | 31 | <span class="keyword">fn</span> <span class="function">bar</span>() { |
32 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>; | 32 | <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>; |
33 | }</code></pre> \ No newline at end of file | 33 | }</code></pre> \ No newline at end of file |
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 33f3caceb..d53a759ee 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs | |||
@@ -2,19 +2,17 @@ | |||
2 | 2 | ||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
4 | 4 | ||
5 | use hir::{Mutability, Ty}; | 5 | use hir::{Mutability, Name}; |
6 | use ra_db::SourceDatabase; | 6 | use ra_db::SourceDatabase; |
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; |
9 | ast::{self, NameOwner}, | ||
10 | AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind, | ||
11 | SyntaxKind::*, | ||
12 | TextRange, T, | ||
13 | }; | ||
14 | 9 | ||
15 | use crate::{ | 10 | use crate::{ |
16 | db::RootDatabase, | 11 | db::RootDatabase, |
17 | references::{classify_name_ref, NameKind::*}, | 12 | references::{ |
13 | classify_name, classify_name_ref, | ||
14 | NameKind::{self, *}, | ||
15 | }, | ||
18 | FileId, | 16 | FileId, |
19 | }; | 17 | }; |
20 | 18 | ||
@@ -40,32 +38,12 @@ fn is_control_keyword(kind: SyntaxKind) -> bool { | |||
40 | } | 38 | } |
41 | } | 39 | } |
42 | 40 | ||
43 | fn is_variable_mutable( | ||
44 | db: &RootDatabase, | ||
45 | analyzer: &hir::SourceAnalyzer, | ||
46 | pat: ast::BindPat, | ||
47 | ) -> bool { | ||
48 | if pat.is_mutable() { | ||
49 | return true; | ||
50 | } | ||
51 | |||
52 | let ty = analyzer.type_of_pat(db, &pat.into()).unwrap_or(Ty::Unknown); | ||
53 | if let Some((_, mutability)) = ty.as_reference() { | ||
54 | match mutability { | ||
55 | Mutability::Shared => false, | ||
56 | Mutability::Mut => true, | ||
57 | } | ||
58 | } else { | ||
59 | false | ||
60 | } | ||
61 | } | ||
62 | |||
63 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { | 41 | pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> { |
64 | let _p = profile("highlight"); | 42 | let _p = profile("highlight"); |
65 | let parse = db.parse(file_id); | 43 | let parse = db.parse(file_id); |
66 | let root = parse.tree().syntax().clone(); | 44 | let root = parse.tree().syntax().clone(); |
67 | 45 | ||
68 | fn calc_binding_hash(file_id: FileId, text: &SmolStr, shadow_count: u32) -> u64 { | 46 | fn calc_binding_hash(file_id: FileId, name: &Name, shadow_count: u32) -> u64 { |
69 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { | 47 | fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 { |
70 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; | 48 | use std::{collections::hash_map::DefaultHasher, hash::Hasher}; |
71 | 49 | ||
@@ -74,13 +52,13 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
74 | hasher.finish() | 52 | hasher.finish() |
75 | } | 53 | } |
76 | 54 | ||
77 | hash((file_id, text, shadow_count)) | 55 | hash((file_id, name, shadow_count)) |
78 | } | 56 | } |
79 | 57 | ||
80 | // Visited nodes to handle highlighting priorities | 58 | // Visited nodes to handle highlighting priorities |
81 | // FIXME: retain only ranges here | 59 | // FIXME: retain only ranges here |
82 | let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); | 60 | let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); |
83 | let mut bindings_shadow_count: FxHashMap<SmolStr, u32> = FxHashMap::default(); | 61 | let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default(); |
84 | 62 | ||
85 | let mut res = Vec::new(); | 63 | let mut res = Vec::new(); |
86 | for node in root.descendants_with_tokens() { | 64 | for node in root.descendants_with_tokens() { |
@@ -100,81 +78,38 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
100 | if node.ancestors().any(|it| it.kind() == ATTR) { | 78 | if node.ancestors().any(|it| it.kind() == ATTR) { |
101 | continue; | 79 | continue; |
102 | } | 80 | } |
103 | if let Some(name_ref) = node.as_node().cloned().and_then(ast::NameRef::cast) { | ||
104 | let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); | ||
105 | match name_kind { | ||
106 | Some(Macro(_)) => "macro", | ||
107 | Some(Field(_)) => "field", | ||
108 | Some(AssocItem(hir::AssocItem::Function(_))) => "function", | ||
109 | Some(AssocItem(hir::AssocItem::Const(_))) => "constant", | ||
110 | Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type", | ||
111 | Some(Def(hir::ModuleDef::Module(_))) => "module", | ||
112 | Some(Def(hir::ModuleDef::Function(_))) => "function", | ||
113 | Some(Def(hir::ModuleDef::Adt(_))) => "type", | ||
114 | Some(Def(hir::ModuleDef::EnumVariant(_))) => "constant", | ||
115 | Some(Def(hir::ModuleDef::Const(_))) => "constant", | ||
116 | Some(Def(hir::ModuleDef::Static(_))) => "constant", | ||
117 | Some(Def(hir::ModuleDef::Trait(_))) => "type", | ||
118 | Some(Def(hir::ModuleDef::TypeAlias(_))) => "type", | ||
119 | Some(Def(hir::ModuleDef::BuiltinType(_))) => "type", | ||
120 | Some(SelfType(_)) => "type", | ||
121 | Some(Pat((_, ptr))) => { | ||
122 | let pat = ptr.to_node(&root); | ||
123 | if let Some(name) = pat.name() { | ||
124 | let text = name.text(); | ||
125 | let shadow_count = | ||
126 | bindings_shadow_count.entry(text.clone()).or_default(); | ||
127 | binding_hash = | ||
128 | Some(calc_binding_hash(file_id, &text, *shadow_count)) | ||
129 | } | ||
130 | 81 | ||
131 | let analyzer = | 82 | let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); |
132 | hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); | 83 | let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); |
133 | if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) { | 84 | |
134 | "variable.mut" | 85 | if let Some(Local(local)) = &name_kind { |
135 | } else { | 86 | if let Some(name) = local.name(db) { |
136 | "variable" | 87 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); |
137 | } | 88 | binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count)) |
138 | } | ||
139 | Some(SelfParam(_)) => "type", | ||
140 | Some(GenericParam(_)) => "type", | ||
141 | None => "text", | ||
142 | } | 89 | } |
143 | } else { | 90 | }; |
144 | "text" | 91 | |
145 | } | 92 | name_kind.map_or("text", |it| highlight_name(db, it)) |
146 | } | 93 | } |
147 | NAME => { | 94 | NAME => { |
148 | if let Some(name) = node.as_node().cloned().and_then(ast::Name::cast) { | 95 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); |
149 | let analyzer = hir::SourceAnalyzer::new(db, file_id, name.syntax(), None); | 96 | let name_kind = classify_name(db, file_id, &name).map(|d| d.kind); |
150 | if let Some(pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { | 97 | |
151 | if let Some(name) = pat.name() { | 98 | if let Some(Local(local)) = &name_kind { |
152 | let text = name.text(); | 99 | if let Some(name) = local.name(db) { |
153 | let shadow_count = | 100 | let shadow_count = bindings_shadow_count.entry(name.clone()).or_default(); |
154 | bindings_shadow_count.entry(text.clone()).or_default(); | 101 | *shadow_count += 1; |
155 | *shadow_count += 1; | 102 | binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count)) |
156 | binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count)) | ||
157 | } | ||
158 | |||
159 | if is_variable_mutable(db, &analyzer, pat) { | ||
160 | "variable.mut" | ||
161 | } else { | ||
162 | "variable" | ||
163 | } | ||
164 | } else { | ||
165 | name.syntax() | ||
166 | .parent() | ||
167 | .map(|x| match x.kind() { | ||
168 | TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => { | ||
169 | "type" | ||
170 | } | ||
171 | RECORD_FIELD_DEF => "field", | ||
172 | _ => "function", | ||
173 | }) | ||
174 | .unwrap_or("function") | ||
175 | } | 103 | } |
176 | } else { | 104 | }; |
177 | "text" | 105 | |
106 | match name_kind { | ||
107 | Some(name_kind) => highlight_name(db, name_kind), | ||
108 | None => name.syntax().parent().map_or("function", |x| match x.kind() { | ||
109 | TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", | ||
110 | RECORD_FIELD_DEF => "field", | ||
111 | _ => "function", | ||
112 | }), | ||
178 | } | 113 | } |
179 | } | 114 | } |
180 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", | 115 | INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", |
@@ -272,6 +207,37 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo | |||
272 | buf | 207 | buf |
273 | } | 208 | } |
274 | 209 | ||
210 | fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { | ||
211 | match name_kind { | ||
212 | Macro(_) => "macro", | ||
213 | Field(_) => "field", | ||
214 | AssocItem(hir::AssocItem::Function(_)) => "function", | ||
215 | AssocItem(hir::AssocItem::Const(_)) => "constant", | ||
216 | AssocItem(hir::AssocItem::TypeAlias(_)) => "type", | ||
217 | Def(hir::ModuleDef::Module(_)) => "module", | ||
218 | Def(hir::ModuleDef::Function(_)) => "function", | ||
219 | Def(hir::ModuleDef::Adt(_)) => "type", | ||
220 | Def(hir::ModuleDef::EnumVariant(_)) => "constant", | ||
221 | Def(hir::ModuleDef::Const(_)) => "constant", | ||
222 | Def(hir::ModuleDef::Static(_)) => "constant", | ||
223 | Def(hir::ModuleDef::Trait(_)) => "type", | ||
224 | Def(hir::ModuleDef::TypeAlias(_)) => "type", | ||
225 | Def(hir::ModuleDef::BuiltinType(_)) => "type", | ||
226 | SelfType(_) => "type", | ||
227 | GenericParam(_) => "type", | ||
228 | Local(local) => { | ||
229 | if local.is_mut(db) { | ||
230 | "variable.mut" | ||
231 | } else { | ||
232 | match local.ty(db).as_reference() { | ||
233 | Some((_, Mutability::Mut)) => "variable.mut", | ||
234 | _ => "variable", | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | |||
275 | //FIXME: like, real html escaping | 241 | //FIXME: like, real html escaping |
276 | fn html_escape(text: &str) -> String { | 242 | fn html_escape(text: &str) -> String { |
277 | text.replace("<", "<").replace(">", ">") | 243 | text.replace("<", "<").replace(">", ">") |