diff options
Diffstat (limited to 'crates/ra_ide_db')
-rw-r--r-- | crates/ra_ide_db/Cargo.toml | 13 | ||||
-rw-r--r-- | crates/ra_ide_db/src/defs.rs | 85 | ||||
-rw-r--r-- | crates/ra_ide_db/src/imports_locator.rs | 27 | ||||
-rw-r--r-- | crates/ra_ide_db/src/line_index.rs | 44 |
4 files changed, 106 insertions, 63 deletions
diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml index ee409e34e..7b285d280 100644 --- a/crates/ra_ide_db/Cargo.toml +++ b/crates/ra_ide_db/Cargo.toml | |||
@@ -11,30 +11,17 @@ doctest = false | |||
11 | wasm = [] | 11 | wasm = [] |
12 | 12 | ||
13 | [dependencies] | 13 | [dependencies] |
14 | either = "1.5.3" | ||
15 | format-buf = "1.0.0" | ||
16 | indexmap = "1.3.2" | ||
17 | itertools = "0.8.2" | ||
18 | join_to_string = "0.1.3" | ||
19 | log = "0.4.8" | 14 | log = "0.4.8" |
20 | rayon = "1.3.0" | 15 | rayon = "1.3.0" |
21 | fst = { version = "0.3.5", default-features = false } | 16 | fst = { version = "0.3.5", default-features = false } |
22 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
23 | unicase = "2.6.0" | ||
24 | superslice = "1.0.0" | 18 | superslice = "1.0.0" |
25 | once_cell = "1.3.1" | ||
26 | 19 | ||
27 | ra_syntax = { path = "../ra_syntax" } | 20 | ra_syntax = { path = "../ra_syntax" } |
28 | ra_text_edit = { path = "../ra_text_edit" } | 21 | ra_text_edit = { path = "../ra_text_edit" } |
29 | ra_db = { path = "../ra_db" } | 22 | ra_db = { path = "../ra_db" } |
30 | ra_cfg = { path = "../ra_cfg" } | ||
31 | ra_fmt = { path = "../ra_fmt" } | ||
32 | ra_prof = { path = "../ra_prof" } | 23 | ra_prof = { path = "../ra_prof" } |
33 | test_utils = { path = "../test_utils" } | ||
34 | 24 | ||
35 | # ra_ide should depend only on the top-level `hir` package. if you need | 25 | # ra_ide should depend only on the top-level `hir` package. if you need |
36 | # something from some `hir_xxx` subpackage, reexport the API via `hir`. | 26 | # something from some `hir_xxx` subpackage, reexport the API via `hir`. |
37 | hir = { path = "../ra_hir", package = "ra_hir" } | 27 | hir = { path = "../ra_hir", package = "ra_hir" } |
38 | |||
39 | [dev-dependencies] | ||
40 | insta = "0.13.1" | ||
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 04c214624..93f32ba85 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | Adt, FieldSource, HasSource, ImplBlock, InFile, Local, MacroDef, Module, ModuleDef, | 9 | Adt, FieldSource, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, Semantics, |
10 | SourceBinder, StructField, TypeParam, | 10 | StructField, TypeParam, |
11 | }; | 11 | }; |
12 | use ra_prof::profile; | 12 | use ra_prof::profile; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ |
@@ -68,78 +68,97 @@ impl NameDefinition { | |||
68 | } | 68 | } |
69 | } | 69 | } |
70 | 70 | ||
71 | pub fn classify_name( | 71 | pub enum NameClass { |
72 | sb: &mut SourceBinder<RootDatabase>, | 72 | NameDefinition(NameDefinition), |
73 | name: InFile<&ast::Name>, | 73 | /// `None` in `if let None = Some(82) {}` |
74 | ) -> Option<NameDefinition> { | 74 | ConstReference(NameDefinition), |
75 | } | ||
76 | |||
77 | impl NameClass { | ||
78 | pub fn into_definition(self) -> Option<NameDefinition> { | ||
79 | match self { | ||
80 | NameClass::NameDefinition(it) => Some(it), | ||
81 | NameClass::ConstReference(_) => None, | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub fn definition(self) -> NameDefinition { | ||
86 | match self { | ||
87 | NameClass::NameDefinition(it) | NameClass::ConstReference(it) => it, | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameClass> { | ||
93 | if let Some(bind_pat) = name.syntax().parent().and_then(ast::BindPat::cast) { | ||
94 | if let Some(def) = sema.resolve_bind_pat_to_const(&bind_pat) { | ||
95 | return Some(NameClass::ConstReference(NameDefinition::ModuleDef(def))); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | classify_name_inner(sema, name).map(NameClass::NameDefinition) | ||
100 | } | ||
101 | |||
102 | fn classify_name_inner(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<NameDefinition> { | ||
75 | let _p = profile("classify_name"); | 103 | let _p = profile("classify_name"); |
76 | let parent = name.value.syntax().parent()?; | 104 | let parent = name.syntax().parent()?; |
77 | 105 | ||
78 | match_ast! { | 106 | match_ast! { |
79 | match parent { | 107 | match parent { |
80 | ast::BindPat(it) => { | 108 | ast::BindPat(it) => { |
81 | let src = name.with_value(it); | 109 | let local = sema.to_def(&it)?; |
82 | let local = sb.to_def(src)?; | ||
83 | Some(NameDefinition::Local(local)) | 110 | Some(NameDefinition::Local(local)) |
84 | }, | 111 | }, |
85 | ast::RecordFieldDef(it) => { | 112 | ast::RecordFieldDef(it) => { |
86 | let src = name.with_value(it); | 113 | let field: hir::StructField = sema.to_def(&it)?; |
87 | let field: hir::StructField = sb.to_def(src)?; | ||
88 | Some(from_struct_field(field)) | 114 | Some(from_struct_field(field)) |
89 | }, | 115 | }, |
90 | ast::Module(it) => { | 116 | ast::Module(it) => { |
91 | let def = sb.to_def(name.with_value(it))?; | 117 | let def = sema.to_def(&it)?; |
92 | Some(from_module_def(def.into())) | 118 | Some(from_module_def(def.into())) |
93 | }, | 119 | }, |
94 | ast::StructDef(it) => { | 120 | ast::StructDef(it) => { |
95 | let src = name.with_value(it); | 121 | let def: hir::Struct = sema.to_def(&it)?; |
96 | let def: hir::Struct = sb.to_def(src)?; | 122 | Some(from_module_def(def.into())) |
123 | }, | ||
124 | ast::UnionDef(it) => { | ||
125 | let def: hir::Union = sema.to_def(&it)?; | ||
97 | Some(from_module_def(def.into())) | 126 | Some(from_module_def(def.into())) |
98 | }, | 127 | }, |
99 | ast::EnumDef(it) => { | 128 | ast::EnumDef(it) => { |
100 | let src = name.with_value(it); | 129 | let def: hir::Enum = sema.to_def(&it)?; |
101 | let def: hir::Enum = sb.to_def(src)?; | ||
102 | Some(from_module_def(def.into())) | 130 | Some(from_module_def(def.into())) |
103 | }, | 131 | }, |
104 | ast::TraitDef(it) => { | 132 | ast::TraitDef(it) => { |
105 | let src = name.with_value(it); | 133 | let def: hir::Trait = sema.to_def(&it)?; |
106 | let def: hir::Trait = sb.to_def(src)?; | ||
107 | Some(from_module_def(def.into())) | 134 | Some(from_module_def(def.into())) |
108 | }, | 135 | }, |
109 | ast::StaticDef(it) => { | 136 | ast::StaticDef(it) => { |
110 | let src = name.with_value(it); | 137 | let def: hir::Static = sema.to_def(&it)?; |
111 | let def: hir::Static = sb.to_def(src)?; | ||
112 | Some(from_module_def(def.into())) | 138 | Some(from_module_def(def.into())) |
113 | }, | 139 | }, |
114 | ast::EnumVariant(it) => { | 140 | ast::EnumVariant(it) => { |
115 | let src = name.with_value(it); | 141 | let def: hir::EnumVariant = sema.to_def(&it)?; |
116 | let def: hir::EnumVariant = sb.to_def(src)?; | ||
117 | Some(from_module_def(def.into())) | 142 | Some(from_module_def(def.into())) |
118 | }, | 143 | }, |
119 | ast::FnDef(it) => { | 144 | ast::FnDef(it) => { |
120 | let src = name.with_value(it); | 145 | let def: hir::Function = sema.to_def(&it)?; |
121 | let def: hir::Function = sb.to_def(src)?; | ||
122 | Some(from_module_def(def.into())) | 146 | Some(from_module_def(def.into())) |
123 | }, | 147 | }, |
124 | ast::ConstDef(it) => { | 148 | ast::ConstDef(it) => { |
125 | let src = name.with_value(it); | 149 | let def: hir::Const = sema.to_def(&it)?; |
126 | let def: hir::Const = sb.to_def(src)?; | ||
127 | Some(from_module_def(def.into())) | 150 | Some(from_module_def(def.into())) |
128 | }, | 151 | }, |
129 | ast::TypeAliasDef(it) => { | 152 | ast::TypeAliasDef(it) => { |
130 | let src = name.with_value(it); | 153 | let def: hir::TypeAlias = sema.to_def(&it)?; |
131 | let def: hir::TypeAlias = sb.to_def(src)?; | ||
132 | Some(from_module_def(def.into())) | 154 | Some(from_module_def(def.into())) |
133 | }, | 155 | }, |
134 | ast::MacroCall(it) => { | 156 | ast::MacroCall(it) => { |
135 | let src = name.with_value(it); | 157 | let def = sema.to_def(&it)?; |
136 | let def = sb.to_def(src.clone())?; | ||
137 | |||
138 | Some(NameDefinition::Macro(def)) | 158 | Some(NameDefinition::Macro(def)) |
139 | }, | 159 | }, |
140 | ast::TypeParam(it) => { | 160 | ast::TypeParam(it) => { |
141 | let src = name.with_value(it); | 161 | let def = sema.to_def(&it)?; |
142 | let def = sb.to_def(src)?; | ||
143 | Some(NameDefinition::TypeParam(def)) | 162 | Some(NameDefinition::TypeParam(def)) |
144 | }, | 163 | }, |
145 | _ => None, | 164 | _ => None, |
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index b8dd358a9..e5fc3c470 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the ra_assists module. | 1 | //! This module contains an import search funcionality that is provided to the ra_assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. |
3 | 3 | ||
4 | use hir::{db::HirDatabase, ModuleDef, SourceBinder}; | 4 | use hir::{ModuleDef, Semantics}; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; | 6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; |
7 | 7 | ||
@@ -12,17 +12,17 @@ use crate::{ | |||
12 | }; | 12 | }; |
13 | 13 | ||
14 | pub struct ImportsLocator<'a> { | 14 | pub struct ImportsLocator<'a> { |
15 | source_binder: SourceBinder<'a, RootDatabase>, | 15 | sema: Semantics<'a, RootDatabase>, |
16 | } | 16 | } |
17 | 17 | ||
18 | impl<'a> ImportsLocator<'a> { | 18 | impl<'a> ImportsLocator<'a> { |
19 | pub fn new(db: &'a RootDatabase) -> Self { | 19 | pub fn new(db: &'a RootDatabase) -> Self { |
20 | Self { source_binder: SourceBinder::new(db) } | 20 | Self { sema: Semantics::new(db) } |
21 | } | 21 | } |
22 | 22 | ||
23 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> { | 23 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> { |
24 | let _p = profile("search_for_imports"); | 24 | let _p = profile("search_for_imports"); |
25 | let db = self.source_binder.db; | 25 | let db = self.sema.db; |
26 | 26 | ||
27 | let project_results = { | 27 | let project_results = { |
28 | let mut query = Query::new(name_to_import.to_string()); | 28 | let mut query = Query::new(name_to_import.to_string()); |
@@ -41,7 +41,7 @@ impl<'a> ImportsLocator<'a> { | |||
41 | project_results | 41 | project_results |
42 | .into_iter() | 42 | .into_iter() |
43 | .chain(lib_results.into_iter()) | 43 | .chain(lib_results.into_iter()) |
44 | .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate)) | 44 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) |
45 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 45 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
46 | NameDefinition::ModuleDef(module_def) => Some(module_def), | 46 | NameDefinition::ModuleDef(module_def) => Some(module_def), |
47 | _ => None, | 47 | _ => None, |
@@ -49,22 +49,17 @@ impl<'a> ImportsLocator<'a> { | |||
49 | .collect() | 49 | .collect() |
50 | } | 50 | } |
51 | 51 | ||
52 | fn get_name_definition( | 52 | fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<NameDefinition> { |
53 | &mut self, | ||
54 | db: &impl HirDatabase, | ||
55 | import_candidate: &FileSymbol, | ||
56 | ) -> Option<NameDefinition> { | ||
57 | let _p = profile("get_name_definition"); | 53 | let _p = profile("get_name_definition"); |
58 | let file_id = import_candidate.file_id.into(); | 54 | let file_id = import_candidate.file_id; |
59 | let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?); | 55 | |
56 | let candidate_node = import_candidate.ptr.to_node(self.sema.parse(file_id).syntax()); | ||
60 | let candidate_name_node = if candidate_node.kind() != NAME { | 57 | let candidate_name_node = if candidate_node.kind() != NAME { |
61 | candidate_node.children().find(|it| it.kind() == NAME)? | 58 | candidate_node.children().find(|it| it.kind() == NAME)? |
62 | } else { | 59 | } else { |
63 | candidate_node | 60 | candidate_node |
64 | }; | 61 | }; |
65 | classify_name( | 62 | let name = ast::Name::cast(candidate_name_node)?; |
66 | &mut self.source_binder, | 63 | classify_name(&self.sema, &name)?.into_definition() |
67 | hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? }, | ||
68 | ) | ||
69 | } | 64 | } |
70 | } | 65 | } |
diff --git a/crates/ra_ide_db/src/line_index.rs b/crates/ra_ide_db/src/line_index.rs index af7b759e5..b9db5c276 100644 --- a/crates/ra_ide_db/src/line_index.rs +++ b/crates/ra_ide_db/src/line_index.rs | |||
@@ -1,7 +1,8 @@ | |||
1 | //! `LineIndex` maps flat `TextUnit` offsets into `(Line, Column)` | 1 | //! `LineIndex` maps flat `TextUnit` offsets into `(Line, Column)` |
2 | //! representation. | 2 | //! representation. |
3 | use std::iter; | ||
3 | 4 | ||
4 | use ra_syntax::TextUnit; | 5 | use ra_syntax::{TextRange, TextUnit}; |
5 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
6 | use superslice::Ext; | 7 | use superslice::Ext; |
7 | 8 | ||
@@ -87,6 +88,19 @@ impl LineIndex { | |||
87 | self.newlines[line_col.line as usize] + col | 88 | self.newlines[line_col.line as usize] + col |
88 | } | 89 | } |
89 | 90 | ||
91 | pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ { | ||
92 | let lo = self.newlines.lower_bound(&range.start()); | ||
93 | let hi = self.newlines.upper_bound(&range.end()); | ||
94 | let all = iter::once(range.start()) | ||
95 | .chain(self.newlines[lo..hi].iter().copied()) | ||
96 | .chain(iter::once(range.end())); | ||
97 | |||
98 | all.clone() | ||
99 | .zip(all.skip(1)) | ||
100 | .map(|(lo, hi)| TextRange::from_to(lo, hi)) | ||
101 | .filter(|it| !it.is_empty()) | ||
102 | } | ||
103 | |||
90 | fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize { | 104 | fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize { |
91 | if let Some(utf16_chars) = self.utf16_lines.get(&line) { | 105 | if let Some(utf16_chars) = self.utf16_lines.get(&line) { |
92 | let mut correction = TextUnit::from_usize(0); | 106 | let mut correction = TextUnit::from_usize(0); |
@@ -221,4 +235,32 @@ const C: char = \"メ メ\"; | |||
221 | 235 | ||
222 | assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); | 236 | assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15)); |
223 | } | 237 | } |
238 | |||
239 | #[test] | ||
240 | fn test_splitlines() { | ||
241 | fn r(lo: u32, hi: u32) -> TextRange { | ||
242 | TextRange::from_to(lo.into(), hi.into()) | ||
243 | } | ||
244 | |||
245 | let text = "a\nbb\nccc\n"; | ||
246 | let line_index = LineIndex::new(text); | ||
247 | |||
248 | let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>(); | ||
249 | let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; | ||
250 | assert_eq!(actual, expected); | ||
251 | |||
252 | let text = ""; | ||
253 | let line_index = LineIndex::new(text); | ||
254 | |||
255 | let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>(); | ||
256 | let expected = vec![]; | ||
257 | assert_eq!(actual, expected); | ||
258 | |||
259 | let text = "\n"; | ||
260 | let line_index = LineIndex::new(text); | ||
261 | |||
262 | let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>(); | ||
263 | let expected = vec![r(0, 1)]; | ||
264 | assert_eq!(actual, expected) | ||
265 | } | ||
224 | } | 266 | } |