aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_db
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_db')
-rw-r--r--crates/ra_ide_db/Cargo.toml13
-rw-r--r--crates/ra_ide_db/src/defs.rs85
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs27
-rw-r--r--crates/ra_ide_db/src/line_index.rs44
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
11wasm = [] 11wasm = []
12 12
13[dependencies] 13[dependencies]
14either = "1.5.3"
15format-buf = "1.0.0"
16indexmap = "1.3.2"
17itertools = "0.8.2"
18join_to_string = "0.1.3"
19log = "0.4.8" 14log = "0.4.8"
20rayon = "1.3.0" 15rayon = "1.3.0"
21fst = { version = "0.3.5", default-features = false } 16fst = { version = "0.3.5", default-features = false }
22rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
23unicase = "2.6.0"
24superslice = "1.0.0" 18superslice = "1.0.0"
25once_cell = "1.3.1"
26 19
27ra_syntax = { path = "../ra_syntax" } 20ra_syntax = { path = "../ra_syntax" }
28ra_text_edit = { path = "../ra_text_edit" } 21ra_text_edit = { path = "../ra_text_edit" }
29ra_db = { path = "../ra_db" } 22ra_db = { path = "../ra_db" }
30ra_cfg = { path = "../ra_cfg" }
31ra_fmt = { path = "../ra_fmt" }
32ra_prof = { path = "../ra_prof" } 23ra_prof = { path = "../ra_prof" }
33test_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`.
37hir = { path = "../ra_hir", package = "ra_hir" } 27hir = { path = "../ra_hir", package = "ra_hir" }
38
39[dev-dependencies]
40insta = "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
8use hir::{ 8use 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};
12use ra_prof::profile; 12use ra_prof::profile;
13use ra_syntax::{ 13use ra_syntax::{
@@ -68,78 +68,97 @@ impl NameDefinition {
68 } 68 }
69} 69}
70 70
71pub fn classify_name( 71pub 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
77impl 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
92pub 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
102fn 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
4use hir::{db::HirDatabase, ModuleDef, SourceBinder}; 4use hir::{ModuleDef, Semantics};
5use ra_prof::profile; 5use ra_prof::profile;
6use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; 6use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
7 7
@@ -12,17 +12,17 @@ use crate::{
12}; 12};
13 13
14pub struct ImportsLocator<'a> { 14pub struct ImportsLocator<'a> {
15 source_binder: SourceBinder<'a, RootDatabase>, 15 sema: Semantics<'a, RootDatabase>,
16} 16}
17 17
18impl<'a> ImportsLocator<'a> { 18impl<'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.
3use std::iter;
3 4
4use ra_syntax::TextUnit; 5use ra_syntax::{TextRange, TextUnit};
5use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
6use superslice::Ext; 7use 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}