diff options
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/goto_definition.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/hover.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 11 | ||||
-rw-r--r-- | crates/ra_ide/src/references.rs | 19 | ||||
-rw-r--r-- | crates/ra_ide/src/references/classify.rs | 100 | ||||
-rw-r--r-- | crates/ra_ide/src/syntax_highlighting.rs | 33 |
6 files changed, 105 insertions, 72 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 79d332e8c..f2b5af321 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{db::AstDatabase, InFile}; | 3 | use hir::{db::AstDatabase, InFile, SourceBinder}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, DocCommentsOwner}, | 5 | ast::{self, DocCommentsOwner}, |
6 | match_ast, AstNode, | 6 | match_ast, AstNode, |
@@ -72,7 +72,8 @@ pub(crate) fn reference_definition( | |||
72 | ) -> ReferenceResult { | 72 | ) -> ReferenceResult { |
73 | use self::ReferenceResult::*; | 73 | use self::ReferenceResult::*; |
74 | 74 | ||
75 | let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind); | 75 | let mut sb = SourceBinder::new(db); |
76 | let name_kind = classify_name_ref(&mut sb, name_ref).map(|d| d.kind); | ||
76 | match name_kind { | 77 | match name_kind { |
77 | Some(Macro(it)) => return Exact(it.to_nav(db)), | 78 | Some(Macro(it)) => return Exact(it.to_nav(db)), |
78 | Some(Field(it)) => return Exact(it.to_nav(db)), | 79 | Some(Field(it)) => return Exact(it.to_nav(db)), |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index 5548681f1..6661e5cb2 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{db::AstDatabase, Adt, HasSource, HirDisplay}; | 3 | use hir::{db::AstDatabase, Adt, HasSource, HirDisplay, SourceBinder}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::find_covering_element, | 6 | algo::find_covering_element, |
@@ -152,13 +152,14 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
152 | 152 | ||
153 | let mut res = HoverResult::new(); | 153 | let mut res = HoverResult::new(); |
154 | 154 | ||
155 | let mut sb = SourceBinder::new(db); | ||
155 | if let Some((range, name_kind)) = match_ast! { | 156 | if let Some((range, name_kind)) = match_ast! { |
156 | match (token.value.parent()) { | 157 | match (token.value.parent()) { |
157 | ast::NameRef(name_ref) => { | 158 | ast::NameRef(name_ref) => { |
158 | classify_name_ref(db, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind)) | 159 | classify_name_ref(&mut sb, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind)) |
159 | }, | 160 | }, |
160 | ast::Name(name) => { | 161 | ast::Name(name) => { |
161 | classify_name(db, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind)) | 162 | classify_name(&mut sb, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind)) |
162 | }, | 163 | }, |
163 | _ => None, | 164 | _ => None, |
164 | } | 165 | } |
@@ -742,7 +743,7 @@ fn func(foo: i32) { if true { <|>foo; }; } | |||
742 | } | 743 | } |
743 | fn foo(bar:u32) { | 744 | fn foo(bar:u32) { |
744 | let a = id!(ba<|>r); | 745 | let a = id!(ba<|>r); |
745 | } | 746 | } |
746 | ", | 747 | ", |
747 | &["u32"], | 748 | &["u32"], |
748 | ); | 749 | ); |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index 8cb0c70dd..e2da96129 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{HirDisplay, SourceAnalyzer}; | 3 | use hir::{HirDisplay, SourceAnalyzer, SourceBinder}; |
4 | use once_cell::unsync::Lazy; | 4 | use once_cell::unsync::Lazy; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -29,22 +29,23 @@ pub(crate) fn inlay_hints( | |||
29 | file: &SourceFile, | 29 | file: &SourceFile, |
30 | max_inlay_hint_length: Option<usize>, | 30 | max_inlay_hint_length: Option<usize>, |
31 | ) -> Vec<InlayHint> { | 31 | ) -> Vec<InlayHint> { |
32 | let mut sb = SourceBinder::new(db); | ||
32 | file.syntax() | 33 | file.syntax() |
33 | .descendants() | 34 | .descendants() |
34 | .flat_map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length)) | 35 | .flat_map(|node| get_inlay_hints(&mut sb, file_id, &node, max_inlay_hint_length)) |
35 | .flatten() | 36 | .flatten() |
36 | .collect() | 37 | .collect() |
37 | } | 38 | } |
38 | 39 | ||
39 | fn get_inlay_hints( | 40 | fn get_inlay_hints( |
40 | db: &RootDatabase, | 41 | sb: &mut SourceBinder<RootDatabase>, |
41 | file_id: FileId, | 42 | file_id: FileId, |
42 | node: &SyntaxNode, | 43 | node: &SyntaxNode, |
43 | max_inlay_hint_length: Option<usize>, | 44 | max_inlay_hint_length: Option<usize>, |
44 | ) -> Option<Vec<InlayHint>> { | 45 | ) -> Option<Vec<InlayHint>> { |
45 | let _p = profile("get_inlay_hints"); | 46 | let _p = profile("get_inlay_hints"); |
46 | let analyzer = | 47 | let db = sb.db; |
47 | Lazy::new(|| SourceAnalyzer::new(db, hir::InFile::new(file_id.into(), node), None)); | 48 | let analyzer = Lazy::new(move || sb.analyze(hir::InFile::new(file_id.into(), node), None)); |
48 | match_ast! { | 49 | match_ast! { |
49 | match node { | 50 | match node { |
50 | ast::LetStmt(it) => { | 51 | ast::LetStmt(it) => { |
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index 2c753dade..5e2fe1905 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -14,7 +14,7 @@ mod name_definition; | |||
14 | mod rename; | 14 | mod rename; |
15 | mod search_scope; | 15 | mod search_scope; |
16 | 16 | ||
17 | use hir::InFile; | 17 | use hir::{InFile, SourceBinder}; |
18 | use once_cell::unsync::Lazy; | 18 | use once_cell::unsync::Lazy; |
19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 19 | use ra_db::{SourceDatabase, SourceDatabaseExt}; |
20 | use ra_prof::profile; | 20 | use ra_prof::profile; |
@@ -171,13 +171,14 @@ fn find_name( | |||
171 | syntax: &SyntaxNode, | 171 | syntax: &SyntaxNode, |
172 | position: FilePosition, | 172 | position: FilePosition, |
173 | ) -> Option<RangeInfo<(String, NameDefinition)>> { | 173 | ) -> Option<RangeInfo<(String, NameDefinition)>> { |
174 | let mut sb = SourceBinder::new(db); | ||
174 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { | 175 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { |
175 | let def = classify_name(db, InFile::new(position.file_id.into(), &name))?; | 176 | let def = classify_name(&mut sb, InFile::new(position.file_id.into(), &name))?; |
176 | let range = name.syntax().text_range(); | 177 | let range = name.syntax().text_range(); |
177 | return Some(RangeInfo::new(range, (name.text().to_string(), def))); | 178 | return Some(RangeInfo::new(range, (name.text().to_string(), def))); |
178 | } | 179 | } |
179 | let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; | 180 | let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; |
180 | let def = classify_name_ref(db, InFile::new(position.file_id.into(), &name_ref))?; | 181 | let def = classify_name_ref(&mut sb, InFile::new(position.file_id.into(), &name_ref))?; |
181 | let range = name_ref.syntax().text_range(); | 182 | let range = name_ref.syntax().text_range(); |
182 | Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) | 183 | Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) |
183 | } | 184 | } |
@@ -195,7 +196,9 @@ fn process_definition( | |||
195 | 196 | ||
196 | for (file_id, search_range) in scope { | 197 | for (file_id, search_range) in scope { |
197 | let text = db.file_text(file_id); | 198 | let text = db.file_text(file_id); |
199 | |||
198 | let parse = Lazy::new(|| SourceFile::parse(&text)); | 200 | let parse = Lazy::new(|| SourceFile::parse(&text)); |
201 | let mut sb = Lazy::new(|| SourceBinder::new(db)); | ||
199 | 202 | ||
200 | for (idx, _) in text.match_indices(pat) { | 203 | for (idx, _) in text.match_indices(pat) { |
201 | let offset = TextUnit::from_usize(idx); | 204 | let offset = TextUnit::from_usize(idx); |
@@ -209,7 +212,11 @@ fn process_definition( | |||
209 | continue; | 212 | continue; |
210 | } | 213 | } |
211 | } | 214 | } |
212 | if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) { | 215 | // FIXME: reuse sb |
216 | // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098 | ||
217 | |||
218 | if let Some(d) = classify_name_ref(&mut sb, InFile::new(file_id.into(), &name_ref)) | ||
219 | { | ||
213 | if d == def { | 220 | if d == def { |
214 | let kind = if name_ref | 221 | let kind = if name_ref |
215 | .syntax() | 222 | .syntax() |
@@ -309,7 +316,7 @@ mod tests { | |||
309 | } | 316 | } |
310 | impl Foo { | 317 | impl Foo { |
311 | fn f() -> i32 { 42 } | 318 | fn f() -> i32 { 42 } |
312 | } | 319 | } |
313 | fn main() { | 320 | fn main() { |
314 | let f: Foo; | 321 | let f: Foo; |
315 | f = Foo {a: Foo::f()}; | 322 | f = Foo {a: Foo::f()}; |
@@ -319,7 +326,7 @@ mod tests { | |||
319 | check_result( | 326 | check_result( |
320 | refs, | 327 | refs, |
321 | "Foo STRUCT_DEF FileId(1) [5; 39) [12; 15) Other", | 328 | "Foo STRUCT_DEF FileId(1) [5; 39) [12; 15) Other", |
322 | &["FileId(1) [142; 145) StructLiteral"], | 329 | &["FileId(1) [138; 141) StructLiteral"], |
323 | ); | 330 | ); |
324 | } | 331 | } |
325 | 332 | ||
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs index 3483a7176..4a6e11e27 100644 --- a/crates/ra_ide/src/references/classify.rs +++ b/crates/ra_ide/src/references/classify.rs | |||
@@ -1,6 +1,6 @@ | |||
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::{FromSource, InFile, Module, ModuleSource, PathResolution, SourceAnalyzer}; | 3 | use hir::{FromSource, InFile, Module, ModuleSource, PathResolution, SourceBinder}; |
4 | use ra_prof::profile; | 4 | use ra_prof::profile; |
5 | use ra_syntax::{ast, match_ast, AstNode}; | 5 | use ra_syntax::{ast, match_ast, AstNode}; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -11,7 +11,10 @@ use super::{ | |||
11 | }; | 11 | }; |
12 | use crate::db::RootDatabase; | 12 | use crate::db::RootDatabase; |
13 | 13 | ||
14 | pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Option<NameDefinition> { | 14 | pub(crate) fn classify_name( |
15 | sb: &mut SourceBinder<RootDatabase>, | ||
16 | name: InFile<&ast::Name>, | ||
17 | ) -> Option<NameDefinition> { | ||
15 | let _p = profile("classify_name"); | 18 | let _p = profile("classify_name"); |
16 | let parent = name.value.syntax().parent()?; | 19 | let parent = name.value.syntax().parent()?; |
17 | 20 | ||
@@ -19,90 +22,89 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti | |||
19 | match parent { | 22 | match parent { |
20 | ast::BindPat(it) => { | 23 | ast::BindPat(it) => { |
21 | let src = name.with_value(it); | 24 | let src = name.with_value(it); |
22 | let local = hir::Local::from_source(db, src)?; | 25 | let local = hir::Local::from_source(sb.db, src)?; |
23 | Some(NameDefinition { | 26 | Some(NameDefinition { |
24 | visibility: None, | 27 | visibility: None, |
25 | container: local.module(db), | 28 | container: local.module(sb.db), |
26 | kind: NameKind::Local(local), | 29 | kind: NameKind::Local(local), |
27 | }) | 30 | }) |
28 | }, | 31 | }, |
29 | ast::RecordFieldDef(it) => { | 32 | ast::RecordFieldDef(it) => { |
30 | let ast = hir::FieldSource::Named(it); | 33 | let src = name.with_value(it); |
31 | let src = name.with_value(ast); | 34 | let field: hir::StructField = sb.to_def(src)?; |
32 | let field = hir::StructField::from_source(db, src)?; | 35 | Some(from_struct_field(sb.db, field)) |
33 | Some(from_struct_field(db, field)) | ||
34 | }, | 36 | }, |
35 | ast::Module(it) => { | 37 | ast::Module(it) => { |
36 | let def = { | 38 | let def = { |
37 | if !it.has_semi() { | 39 | if !it.has_semi() { |
38 | let ast = hir::ModuleSource::Module(it); | 40 | let ast = hir::ModuleSource::Module(it); |
39 | let src = name.with_value(ast); | 41 | let src = name.with_value(ast); |
40 | hir::Module::from_definition(db, src) | 42 | hir::Module::from_definition(sb.db, src) |
41 | } else { | 43 | } else { |
42 | let src = name.with_value(it); | 44 | let src = name.with_value(it); |
43 | hir::Module::from_declaration(db, src) | 45 | hir::Module::from_declaration(sb.db, src) |
44 | } | 46 | } |
45 | }?; | 47 | }?; |
46 | Some(from_module_def(db, def.into(), None)) | 48 | Some(from_module_def(sb.db, def.into(), None)) |
47 | }, | 49 | }, |
48 | ast::StructDef(it) => { | 50 | ast::StructDef(it) => { |
49 | let src = name.with_value(it); | 51 | let src = name.with_value(it); |
50 | let def = hir::Struct::from_source(db, src)?; | 52 | let def: hir::Struct = sb.to_def(src)?; |
51 | Some(from_module_def(db, def.into(), None)) | 53 | Some(from_module_def(sb.db, def.into(), None)) |
52 | }, | 54 | }, |
53 | ast::EnumDef(it) => { | 55 | ast::EnumDef(it) => { |
54 | let src = name.with_value(it); | 56 | let src = name.with_value(it); |
55 | let def = hir::Enum::from_source(db, src)?; | 57 | let def: hir::Enum = sb.to_def(src)?; |
56 | Some(from_module_def(db, def.into(), None)) | 58 | Some(from_module_def(sb.db, def.into(), None)) |
57 | }, | 59 | }, |
58 | ast::TraitDef(it) => { | 60 | ast::TraitDef(it) => { |
59 | let src = name.with_value(it); | 61 | let src = name.with_value(it); |
60 | let def = hir::Trait::from_source(db, src)?; | 62 | let def: hir::Trait = sb.to_def(src)?; |
61 | Some(from_module_def(db, def.into(), None)) | 63 | Some(from_module_def(sb.db, def.into(), None)) |
62 | }, | 64 | }, |
63 | ast::StaticDef(it) => { | 65 | ast::StaticDef(it) => { |
64 | let src = name.with_value(it); | 66 | let src = name.with_value(it); |
65 | let def = hir::Static::from_source(db, src)?; | 67 | let def: hir::Static = sb.to_def(src)?; |
66 | Some(from_module_def(db, def.into(), None)) | 68 | Some(from_module_def(sb.db, def.into(), None)) |
67 | }, | 69 | }, |
68 | ast::EnumVariant(it) => { | 70 | ast::EnumVariant(it) => { |
69 | let src = name.with_value(it); | 71 | let src = name.with_value(it); |
70 | let def = hir::EnumVariant::from_source(db, src)?; | 72 | let def: hir::EnumVariant = sb.to_def(src)?; |
71 | Some(from_module_def(db, def.into(), None)) | 73 | Some(from_module_def(sb.db, def.into(), None)) |
72 | }, | 74 | }, |
73 | ast::FnDef(it) => { | 75 | ast::FnDef(it) => { |
74 | let src = name.with_value(it); | 76 | let src = name.with_value(it); |
75 | let def = hir::Function::from_source(db, src)?; | 77 | let def: hir::Function = sb.to_def(src)?; |
76 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | 78 | if parent.parent().and_then(ast::ItemList::cast).is_some() { |
77 | Some(from_assoc_item(db, def.into())) | 79 | Some(from_assoc_item(sb.db, def.into())) |
78 | } else { | 80 | } else { |
79 | Some(from_module_def(db, def.into(), None)) | 81 | Some(from_module_def(sb.db, def.into(), None)) |
80 | } | 82 | } |
81 | }, | 83 | }, |
82 | ast::ConstDef(it) => { | 84 | ast::ConstDef(it) => { |
83 | let src = name.with_value(it); | 85 | let src = name.with_value(it); |
84 | let def = hir::Const::from_source(db, src)?; | 86 | let def: hir::Const = sb.to_def(src)?; |
85 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | 87 | if parent.parent().and_then(ast::ItemList::cast).is_some() { |
86 | Some(from_assoc_item(db, def.into())) | 88 | Some(from_assoc_item(sb.db, def.into())) |
87 | } else { | 89 | } else { |
88 | Some(from_module_def(db, def.into(), None)) | 90 | Some(from_module_def(sb.db, def.into(), None)) |
89 | } | 91 | } |
90 | }, | 92 | }, |
91 | ast::TypeAliasDef(it) => { | 93 | ast::TypeAliasDef(it) => { |
92 | let src = name.with_value(it); | 94 | let src = name.with_value(it); |
93 | let def = hir::TypeAlias::from_source(db, src)?; | 95 | let def: hir::TypeAlias = sb.to_def(src)?; |
94 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | 96 | if parent.parent().and_then(ast::ItemList::cast).is_some() { |
95 | Some(from_assoc_item(db, def.into())) | 97 | Some(from_assoc_item(sb.db, def.into())) |
96 | } else { | 98 | } else { |
97 | Some(from_module_def(db, def.into(), None)) | 99 | Some(from_module_def(sb.db, def.into(), None)) |
98 | } | 100 | } |
99 | }, | 101 | }, |
100 | ast::MacroCall(it) => { | 102 | ast::MacroCall(it) => { |
101 | let src = name.with_value(it); | 103 | let src = name.with_value(it); |
102 | let def = hir::MacroDef::from_source(db, src.clone())?; | 104 | let def = hir::MacroDef::from_source(sb.db, src.clone())?; |
103 | 105 | ||
104 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | 106 | let module_src = ModuleSource::from_child_node(sb.db, src.as_ref().map(|it| it.syntax())); |
105 | let module = Module::from_definition(db, src.with_value(module_src))?; | 107 | let module = Module::from_definition(sb.db, src.with_value(module_src))?; |
106 | 108 | ||
107 | Some(NameDefinition { | 109 | Some(NameDefinition { |
108 | visibility: None, | 110 | visibility: None, |
@@ -112,10 +114,10 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti | |||
112 | }, | 114 | }, |
113 | ast::TypeParam(it) => { | 115 | ast::TypeParam(it) => { |
114 | let src = name.with_value(it); | 116 | let src = name.with_value(it); |
115 | let def = hir::TypeParam::from_source(db, src)?; | 117 | let def = hir::TypeParam::from_source(sb.db, src)?; |
116 | Some(NameDefinition { | 118 | Some(NameDefinition { |
117 | visibility: None, | 119 | visibility: None, |
118 | container: def.module(db), | 120 | container: def.module(sb.db), |
119 | kind: NameKind::TypeParam(def), | 121 | kind: NameKind::TypeParam(def), |
120 | }) | 122 | }) |
121 | }, | 123 | }, |
@@ -125,25 +127,25 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti | |||
125 | } | 127 | } |
126 | 128 | ||
127 | pub(crate) fn classify_name_ref( | 129 | pub(crate) fn classify_name_ref( |
128 | db: &RootDatabase, | 130 | sb: &mut SourceBinder<RootDatabase>, |
129 | name_ref: InFile<&ast::NameRef>, | 131 | name_ref: InFile<&ast::NameRef>, |
130 | ) -> Option<NameDefinition> { | 132 | ) -> Option<NameDefinition> { |
131 | let _p = profile("classify_name_ref"); | 133 | let _p = profile("classify_name_ref"); |
132 | 134 | ||
133 | let parent = name_ref.value.syntax().parent()?; | 135 | let parent = name_ref.value.syntax().parent()?; |
134 | let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None); | 136 | let analyzer = sb.analyze(name_ref.map(|it| it.syntax()), None); |
135 | 137 | ||
136 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { | 138 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { |
137 | tested_by!(goto_def_for_methods); | 139 | tested_by!(goto_def_for_methods); |
138 | if let Some(func) = analyzer.resolve_method_call(&method_call) { | 140 | if let Some(func) = analyzer.resolve_method_call(&method_call) { |
139 | return Some(from_assoc_item(db, func.into())); | 141 | return Some(from_assoc_item(sb.db, func.into())); |
140 | } | 142 | } |
141 | } | 143 | } |
142 | 144 | ||
143 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { | 145 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { |
144 | tested_by!(goto_def_for_fields); | 146 | tested_by!(goto_def_for_fields); |
145 | if let Some(field) = analyzer.resolve_field(&field_expr) { | 147 | if let Some(field) = analyzer.resolve_field(&field_expr) { |
146 | return Some(from_struct_field(db, field)); | 148 | return Some(from_struct_field(sb.db, field)); |
147 | } | 149 | } |
148 | } | 150 | } |
149 | 151 | ||
@@ -151,30 +153,32 @@ pub(crate) fn classify_name_ref( | |||
151 | tested_by!(goto_def_for_record_fields); | 153 | tested_by!(goto_def_for_record_fields); |
152 | tested_by!(goto_def_for_field_init_shorthand); | 154 | tested_by!(goto_def_for_field_init_shorthand); |
153 | if let Some(field_def) = analyzer.resolve_record_field(&record_field) { | 155 | if let Some(field_def) = analyzer.resolve_record_field(&record_field) { |
154 | return Some(from_struct_field(db, field_def)); | 156 | return Some(from_struct_field(sb.db, field_def)); |
155 | } | 157 | } |
156 | } | 158 | } |
157 | 159 | ||
158 | let ast = ModuleSource::from_child_node(db, name_ref.with_value(&parent)); | 160 | let ast = ModuleSource::from_child_node(sb.db, name_ref.with_value(&parent)); |
159 | // FIXME: find correct container and visibility for each case | 161 | // FIXME: find correct container and visibility for each case |
160 | let container = Module::from_definition(db, name_ref.with_value(ast))?; | 162 | let container = Module::from_definition(sb.db, name_ref.with_value(ast))?; |
161 | let visibility = None; | 163 | let visibility = None; |
162 | 164 | ||
163 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { | 165 | if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { |
164 | tested_by!(goto_def_for_macros); | 166 | tested_by!(goto_def_for_macros); |
165 | if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(¯o_call)) { | 167 | if let Some(macro_def) = |
168 | analyzer.resolve_macro_call(sb.db, name_ref.with_value(¯o_call)) | ||
169 | { | ||
166 | let kind = NameKind::Macro(macro_def); | 170 | let kind = NameKind::Macro(macro_def); |
167 | return Some(NameDefinition { kind, container, visibility }); | 171 | return Some(NameDefinition { kind, container, visibility }); |
168 | } | 172 | } |
169 | } | 173 | } |
170 | 174 | ||
171 | let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?; | 175 | let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?; |
172 | let resolved = analyzer.resolve_path(db, &path)?; | 176 | let resolved = analyzer.resolve_path(sb.db, &path)?; |
173 | match resolved { | 177 | match resolved { |
174 | PathResolution::Def(def) => Some(from_module_def(db, def, Some(container))), | 178 | PathResolution::Def(def) => Some(from_module_def(sb.db, def, Some(container))), |
175 | PathResolution::AssocItem(item) => Some(from_assoc_item(db, item)), | 179 | PathResolution::AssocItem(item) => Some(from_assoc_item(sb.db, item)), |
176 | PathResolution::Local(local) => { | 180 | PathResolution::Local(local) => { |
177 | let container = local.module(db); | 181 | let container = local.module(sb.db); |
178 | let kind = NameKind::Local(local); | 182 | let kind = NameKind::Local(local); |
179 | Some(NameDefinition { kind, container, visibility: None }) | 183 | Some(NameDefinition { kind, container, visibility: None }) |
180 | } | 184 | } |
@@ -188,7 +192,7 @@ pub(crate) fn classify_name_ref( | |||
188 | } | 192 | } |
189 | PathResolution::SelfType(impl_block) => { | 193 | PathResolution::SelfType(impl_block) => { |
190 | let kind = NameKind::SelfType(impl_block); | 194 | let kind = NameKind::SelfType(impl_block); |
191 | let container = impl_block.module(db); | 195 | let container = impl_block.module(sb.db); |
192 | Some(NameDefinition { kind, container, visibility }) | 196 | Some(NameDefinition { kind, container, visibility }) |
193 | } | 197 | } |
194 | } | 198 | } |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index 56a36f587..0411977b9 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
4 | 4 | ||
5 | use hir::{InFile, Name}; | 5 | use hir::{InFile, Name, SourceBinder}; |
6 | use ra_db::SourceDatabase; | 6 | use ra_db::SourceDatabase; |
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; | 8 | use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; |
@@ -84,6 +84,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
84 | hash((file_id, name, shadow_count)) | 84 | hash((file_id, name, shadow_count)) |
85 | } | 85 | } |
86 | 86 | ||
87 | let mut sb = SourceBinder::new(db); | ||
88 | |||
87 | // Visited nodes to handle highlighting priorities | 89 | // Visited nodes to handle highlighting priorities |
88 | // FIXME: retain only ranges here | 90 | // FIXME: retain only ranges here |
89 | let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); | 91 | let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default(); |
@@ -108,8 +110,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
108 | NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue, | 110 | NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue, |
109 | NAME_REF => { | 111 | NAME_REF => { |
110 | let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); | 112 | let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); |
111 | let name_kind = | 113 | let name_kind = classify_name_ref(&mut sb, InFile::new(file_id.into(), &name_ref)) |
112 | classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind); | 114 | .map(|d| d.kind); |
113 | match name_kind { | 115 | match name_kind { |
114 | Some(name_kind) => { | 116 | Some(name_kind) => { |
115 | if let Local(local) = &name_kind { | 117 | if let Local(local) = &name_kind { |
@@ -129,7 +131,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa | |||
129 | NAME => { | 131 | NAME => { |
130 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); | 132 | let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); |
131 | let name_kind = | 133 | let name_kind = |
132 | classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind); | 134 | classify_name(&mut sb, InFile::new(file_id.into(), &name)).map(|d| d.kind); |
133 | 135 | ||
134 | if let Some(Local(local)) = &name_kind { | 136 | if let Some(Local(local)) = &name_kind { |
135 | if let Some(name) = local.name(db) { | 137 | if let Some(name) = local.name(db) { |
@@ -308,9 +310,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
308 | 310 | ||
309 | #[cfg(test)] | 311 | #[cfg(test)] |
310 | mod tests { | 312 | mod tests { |
311 | use crate::mock_analysis::single_file; | 313 | use std::fs; |
314 | |||
312 | use test_utils::{assert_eq_text, project_dir, read_text}; | 315 | use test_utils::{assert_eq_text, project_dir, read_text}; |
313 | 316 | ||
317 | use crate::mock_analysis::{single_file, MockAnalysis}; | ||
318 | |||
314 | #[test] | 319 | #[test] |
315 | fn test_highlighting() { | 320 | fn test_highlighting() { |
316 | let (analysis, file_id) = single_file( | 321 | let (analysis, file_id) = single_file( |
@@ -357,7 +362,7 @@ impl<X> E<X> { | |||
357 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html"); | 362 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlighting.html"); |
358 | let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); | 363 | let actual_html = &analysis.highlight_as_html(file_id, false).unwrap(); |
359 | let expected_html = &read_text(&dst_file); | 364 | let expected_html = &read_text(&dst_file); |
360 | std::fs::write(dst_file, &actual_html).unwrap(); | 365 | fs::write(dst_file, &actual_html).unwrap(); |
361 | assert_eq_text!(expected_html, actual_html); | 366 | assert_eq_text!(expected_html, actual_html); |
362 | } | 367 | } |
363 | 368 | ||
@@ -383,7 +388,21 @@ fn bar() { | |||
383 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html"); | 388 | let dst_file = project_dir().join("crates/ra_ide/src/snapshots/rainbow_highlighting.html"); |
384 | let actual_html = &analysis.highlight_as_html(file_id, true).unwrap(); | 389 | let actual_html = &analysis.highlight_as_html(file_id, true).unwrap(); |
385 | let expected_html = &read_text(&dst_file); | 390 | let expected_html = &read_text(&dst_file); |
386 | std::fs::write(dst_file, &actual_html).unwrap(); | 391 | fs::write(dst_file, &actual_html).unwrap(); |
387 | assert_eq_text!(expected_html, actual_html); | 392 | assert_eq_text!(expected_html, actual_html); |
388 | } | 393 | } |
394 | |||
395 | #[test] | ||
396 | fn accidentally_quadratic() { | ||
397 | let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic"); | ||
398 | let src = fs::read_to_string(file).unwrap(); | ||
399 | |||
400 | let mut mock = MockAnalysis::new(); | ||
401 | let file_id = mock.add_file("/main.rs", &src); | ||
402 | let host = mock.analysis_host(); | ||
403 | |||
404 | // let t = std::time::Instant::now(); | ||
405 | let _ = host.analysis().highlight(file_id).unwrap(); | ||
406 | // eprintln!("elapsed: {:?}", t.elapsed()); | ||
407 | } | ||
389 | } | 408 | } |