diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-02-06 15:27:23 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-02-06 15:27:23 +0000 |
commit | ff0f0fc31e84deb7aebf8ab6ec510051d531c9f2 (patch) | |
tree | 696f118a3555b446f930becee802574e344d1afc /crates/ra_ide/src/references | |
parent | aa571e378b67134903a66094cf9aa7b2ce7118e8 (diff) | |
parent | dfbe96750b69fc69e64f3a6094e2c1d574ab42fa (diff) |
Merge #3031
3031: Move imports locator to ide_db r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/references')
-rw-r--r-- | crates/ra_ide/src/references/classify.rs | 112 | ||||
-rw-r--r-- | crates/ra_ide/src/references/name_definition.rs | 85 | ||||
-rw-r--r-- | crates/ra_ide/src/references/search_scope.rs | 102 |
3 files changed, 53 insertions, 246 deletions
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs index 758ea4e8b..0326fd379 100644 --- a/crates/ra_ide/src/references/classify.rs +++ b/crates/ra_ide/src/references/classify.rs | |||
@@ -2,119 +2,13 @@ | |||
2 | 2 | ||
3 | use hir::{InFile, PathResolution, SourceBinder}; | 3 | use hir::{InFile, 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, AstNode}; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | 7 | ||
8 | use super::{ | 8 | use super::{NameDefinition, NameKind}; |
9 | name_definition::{from_assoc_item, from_module_def, from_struct_field}, | ||
10 | NameDefinition, NameKind, | ||
11 | }; | ||
12 | use ra_ide_db::RootDatabase; | 9 | use ra_ide_db::RootDatabase; |
13 | 10 | ||
14 | pub(crate) fn classify_name( | 11 | pub use ra_ide_db::defs::{classify_name, from_assoc_item, from_module_def, from_struct_field}; |
15 | sb: &mut SourceBinder<RootDatabase>, | ||
16 | name: InFile<&ast::Name>, | ||
17 | ) -> Option<NameDefinition> { | ||
18 | let _p = profile("classify_name"); | ||
19 | let parent = name.value.syntax().parent()?; | ||
20 | |||
21 | match_ast! { | ||
22 | match parent { | ||
23 | ast::BindPat(it) => { | ||
24 | let src = name.with_value(it); | ||
25 | let local = sb.to_def(src)?; | ||
26 | Some(NameDefinition { | ||
27 | visibility: None, | ||
28 | container: local.module(sb.db), | ||
29 | kind: NameKind::Local(local), | ||
30 | }) | ||
31 | }, | ||
32 | ast::RecordFieldDef(it) => { | ||
33 | let src = name.with_value(it); | ||
34 | let field: hir::StructField = sb.to_def(src)?; | ||
35 | Some(from_struct_field(sb.db, field)) | ||
36 | }, | ||
37 | ast::Module(it) => { | ||
38 | let def = sb.to_def(name.with_value(it))?; | ||
39 | Some(from_module_def(sb.db, def.into(), None)) | ||
40 | }, | ||
41 | ast::StructDef(it) => { | ||
42 | let src = name.with_value(it); | ||
43 | let def: hir::Struct = sb.to_def(src)?; | ||
44 | Some(from_module_def(sb.db, def.into(), None)) | ||
45 | }, | ||
46 | ast::EnumDef(it) => { | ||
47 | let src = name.with_value(it); | ||
48 | let def: hir::Enum = sb.to_def(src)?; | ||
49 | Some(from_module_def(sb.db, def.into(), None)) | ||
50 | }, | ||
51 | ast::TraitDef(it) => { | ||
52 | let src = name.with_value(it); | ||
53 | let def: hir::Trait = sb.to_def(src)?; | ||
54 | Some(from_module_def(sb.db, def.into(), None)) | ||
55 | }, | ||
56 | ast::StaticDef(it) => { | ||
57 | let src = name.with_value(it); | ||
58 | let def: hir::Static = sb.to_def(src)?; | ||
59 | Some(from_module_def(sb.db, def.into(), None)) | ||
60 | }, | ||
61 | ast::EnumVariant(it) => { | ||
62 | let src = name.with_value(it); | ||
63 | let def: hir::EnumVariant = sb.to_def(src)?; | ||
64 | Some(from_module_def(sb.db, def.into(), None)) | ||
65 | }, | ||
66 | ast::FnDef(it) => { | ||
67 | let src = name.with_value(it); | ||
68 | let def: hir::Function = sb.to_def(src)?; | ||
69 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
70 | Some(from_assoc_item(sb.db, def.into())) | ||
71 | } else { | ||
72 | Some(from_module_def(sb.db, def.into(), None)) | ||
73 | } | ||
74 | }, | ||
75 | ast::ConstDef(it) => { | ||
76 | let src = name.with_value(it); | ||
77 | let def: hir::Const = sb.to_def(src)?; | ||
78 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
79 | Some(from_assoc_item(sb.db, def.into())) | ||
80 | } else { | ||
81 | Some(from_module_def(sb.db, def.into(), None)) | ||
82 | } | ||
83 | }, | ||
84 | ast::TypeAliasDef(it) => { | ||
85 | let src = name.with_value(it); | ||
86 | let def: hir::TypeAlias = sb.to_def(src)?; | ||
87 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
88 | Some(from_assoc_item(sb.db, def.into())) | ||
89 | } else { | ||
90 | Some(from_module_def(sb.db, def.into(), None)) | ||
91 | } | ||
92 | }, | ||
93 | ast::MacroCall(it) => { | ||
94 | let src = name.with_value(it); | ||
95 | let def = sb.to_def(src.clone())?; | ||
96 | |||
97 | let module = sb.to_module_def(src.file_id.original_file(sb.db))?; | ||
98 | |||
99 | Some(NameDefinition { | ||
100 | visibility: None, | ||
101 | container: module, | ||
102 | kind: NameKind::Macro(def), | ||
103 | }) | ||
104 | }, | ||
105 | ast::TypeParam(it) => { | ||
106 | let src = name.with_value(it); | ||
107 | let def = sb.to_def(src)?; | ||
108 | Some(NameDefinition { | ||
109 | visibility: None, | ||
110 | container: def.module(sb.db), | ||
111 | kind: NameKind::TypeParam(def), | ||
112 | }) | ||
113 | }, | ||
114 | _ => None, | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | 12 | ||
119 | pub(crate) fn classify_name_ref( | 13 | pub(crate) fn classify_name_ref( |
120 | sb: &mut SourceBinder<RootDatabase>, | 14 | sb: &mut SourceBinder<RootDatabase>, |
diff --git a/crates/ra_ide/src/references/name_definition.rs b/crates/ra_ide/src/references/name_definition.rs deleted file mode 100644 index 71565e6d3..000000000 --- a/crates/ra_ide/src/references/name_definition.rs +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | //! `NameDefinition` keeps information about the element we want to search references for. | ||
2 | //! The element is represented by `NameKind`. It's located inside some `container` and | ||
3 | //! has a `visibility`, which defines a search scope. | ||
4 | //! Note that the reference search is possible for not all of the classified items. | ||
5 | |||
6 | use hir::{ | ||
7 | Adt, AssocItem, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, StructField, | ||
8 | TypeParam, VariantDef, | ||
9 | }; | ||
10 | use ra_syntax::{ast, ast::VisibilityOwner}; | ||
11 | |||
12 | use ra_ide_db::RootDatabase; | ||
13 | |||
14 | #[derive(Debug, PartialEq, Eq)] | ||
15 | pub enum NameKind { | ||
16 | Macro(MacroDef), | ||
17 | Field(StructField), | ||
18 | AssocItem(AssocItem), | ||
19 | Def(ModuleDef), | ||
20 | SelfType(ImplBlock), | ||
21 | Local(Local), | ||
22 | TypeParam(TypeParam), | ||
23 | } | ||
24 | |||
25 | #[derive(PartialEq, Eq)] | ||
26 | pub(crate) struct NameDefinition { | ||
27 | pub visibility: Option<ast::Visibility>, | ||
28 | /// FIXME: this doesn't really make sense. For example, builtin types don't | ||
29 | /// really have a module. | ||
30 | pub container: Module, | ||
31 | pub kind: NameKind, | ||
32 | } | ||
33 | |||
34 | pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { | ||
35 | let container = item.module(db); | ||
36 | let visibility = match item { | ||
37 | AssocItem::Function(f) => f.source(db).value.visibility(), | ||
38 | AssocItem::Const(c) => c.source(db).value.visibility(), | ||
39 | AssocItem::TypeAlias(a) => a.source(db).value.visibility(), | ||
40 | }; | ||
41 | let kind = NameKind::AssocItem(item); | ||
42 | NameDefinition { kind, container, visibility } | ||
43 | } | ||
44 | |||
45 | pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition { | ||
46 | let kind = NameKind::Field(field); | ||
47 | let parent = field.parent_def(db); | ||
48 | let container = parent.module(db); | ||
49 | let visibility = match parent { | ||
50 | VariantDef::Struct(s) => s.source(db).value.visibility(), | ||
51 | VariantDef::Union(e) => e.source(db).value.visibility(), | ||
52 | VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(), | ||
53 | }; | ||
54 | NameDefinition { kind, container, visibility } | ||
55 | } | ||
56 | |||
57 | pub(super) fn from_module_def( | ||
58 | db: &RootDatabase, | ||
59 | def: ModuleDef, | ||
60 | module: Option<Module>, | ||
61 | ) -> NameDefinition { | ||
62 | let kind = NameKind::Def(def); | ||
63 | let (container, visibility) = match def { | ||
64 | ModuleDef::Module(it) => { | ||
65 | let container = it.parent(db).or_else(|| Some(it)).unwrap(); | ||
66 | let visibility = it.declaration_source(db).and_then(|s| s.value.visibility()); | ||
67 | (container, visibility) | ||
68 | } | ||
69 | ModuleDef::EnumVariant(it) => { | ||
70 | let container = it.module(db); | ||
71 | let visibility = it.source(db).value.parent_enum().visibility(); | ||
72 | (container, visibility) | ||
73 | } | ||
74 | ModuleDef::Function(it) => (it.module(db), it.source(db).value.visibility()), | ||
75 | ModuleDef::Const(it) => (it.module(db), it.source(db).value.visibility()), | ||
76 | ModuleDef::Static(it) => (it.module(db), it.source(db).value.visibility()), | ||
77 | ModuleDef::Trait(it) => (it.module(db), it.source(db).value.visibility()), | ||
78 | ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).value.visibility()), | ||
79 | ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).value.visibility()), | ||
80 | ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).value.visibility()), | ||
81 | ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).value.visibility()), | ||
82 | ModuleDef::BuiltinType(..) => (module.unwrap(), None), | ||
83 | }; | ||
84 | NameDefinition { kind, container, visibility } | ||
85 | } | ||
diff --git a/crates/ra_ide/src/references/search_scope.rs b/crates/ra_ide/src/references/search_scope.rs index 97c65c2cd..279f57be0 100644 --- a/crates/ra_ide/src/references/search_scope.rs +++ b/crates/ra_ide/src/references/search_scope.rs | |||
@@ -19,59 +19,13 @@ pub struct SearchScope { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | impl SearchScope { | 21 | impl SearchScope { |
22 | fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope { | 22 | pub(crate) fn for_def(def: &NameDefinition, db: &RootDatabase) -> SearchScope { |
23 | SearchScope { entries } | ||
24 | } | ||
25 | pub fn single_file(file: FileId) -> SearchScope { | ||
26 | SearchScope::new(std::iter::once((file, None)).collect()) | ||
27 | } | ||
28 | pub(crate) fn intersection(&self, other: &SearchScope) -> SearchScope { | ||
29 | let (mut small, mut large) = (&self.entries, &other.entries); | ||
30 | if small.len() > large.len() { | ||
31 | mem::swap(&mut small, &mut large) | ||
32 | } | ||
33 | |||
34 | let res = small | ||
35 | .iter() | ||
36 | .filter_map(|(file_id, r1)| { | ||
37 | let r2 = large.get(file_id)?; | ||
38 | let r = intersect_ranges(*r1, *r2)?; | ||
39 | Some((*file_id, r)) | ||
40 | }) | ||
41 | .collect(); | ||
42 | return SearchScope::new(res); | ||
43 | |||
44 | fn intersect_ranges( | ||
45 | r1: Option<TextRange>, | ||
46 | r2: Option<TextRange>, | ||
47 | ) -> Option<Option<TextRange>> { | ||
48 | match (r1, r2) { | ||
49 | (None, r) | (r, None) => Some(r), | ||
50 | (Some(r1), Some(r2)) => { | ||
51 | let r = r1.intersection(&r2)?; | ||
52 | Some(Some(r)) | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | impl IntoIterator for SearchScope { | ||
60 | type Item = (FileId, Option<TextRange>); | ||
61 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>; | ||
62 | fn into_iter(self) -> Self::IntoIter { | ||
63 | self.entries.into_iter() | ||
64 | } | ||
65 | } | ||
66 | |||
67 | impl NameDefinition { | ||
68 | pub(crate) fn search_scope(&self, db: &RootDatabase) -> SearchScope { | ||
69 | let _p = profile("search_scope"); | 23 | let _p = profile("search_scope"); |
70 | 24 | ||
71 | let module_src = self.container.definition_source(db); | 25 | let module_src = def.container.definition_source(db); |
72 | let file_id = module_src.file_id.original_file(db); | 26 | let file_id = module_src.file_id.original_file(db); |
73 | 27 | ||
74 | if let NameKind::Local(var) = self.kind { | 28 | if let NameKind::Local(var) = def.kind { |
75 | let range = match var.parent(db) { | 29 | let range = match var.parent(db) { |
76 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), | 30 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), |
77 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), | 31 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), |
@@ -82,10 +36,10 @@ impl NameDefinition { | |||
82 | return SearchScope::new(res); | 36 | return SearchScope::new(res); |
83 | } | 37 | } |
84 | 38 | ||
85 | let vis = self.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or_default(); | 39 | let vis = def.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or_default(); |
86 | 40 | ||
87 | if vis.as_str() == "pub(super)" { | 41 | if vis.as_str() == "pub(super)" { |
88 | if let Some(parent_module) = self.container.parent(db) { | 42 | if let Some(parent_module) = def.container.parent(db) { |
89 | let mut res = FxHashMap::default(); | 43 | let mut res = FxHashMap::default(); |
90 | let parent_src = parent_module.definition_source(db); | 44 | let parent_src = parent_module.definition_source(db); |
91 | let file_id = parent_src.file_id.original_file(db); | 45 | let file_id = parent_src.file_id.original_file(db); |
@@ -118,7 +72,7 @@ impl NameDefinition { | |||
118 | return SearchScope::new(res); | 72 | return SearchScope::new(res); |
119 | } | 73 | } |
120 | if vis.as_str() == "pub" { | 74 | if vis.as_str() == "pub" { |
121 | let krate = self.container.krate(); | 75 | let krate = def.container.krate(); |
122 | for rev_dep in krate.reverse_dependencies(db) { | 76 | for rev_dep in krate.reverse_dependencies(db) { |
123 | let root_file = rev_dep.root_file(db); | 77 | let root_file = rev_dep.root_file(db); |
124 | let source_root_id = db.file_source_root(root_file); | 78 | let source_root_id = db.file_source_root(root_file); |
@@ -137,4 +91,48 @@ impl NameDefinition { | |||
137 | res.insert(file_id, range); | 91 | res.insert(file_id, range); |
138 | SearchScope::new(res) | 92 | SearchScope::new(res) |
139 | } | 93 | } |
94 | |||
95 | fn new(entries: FxHashMap<FileId, Option<TextRange>>) -> SearchScope { | ||
96 | SearchScope { entries } | ||
97 | } | ||
98 | pub fn single_file(file: FileId) -> SearchScope { | ||
99 | SearchScope::new(std::iter::once((file, None)).collect()) | ||
100 | } | ||
101 | pub(crate) fn intersection(&self, other: &SearchScope) -> SearchScope { | ||
102 | let (mut small, mut large) = (&self.entries, &other.entries); | ||
103 | if small.len() > large.len() { | ||
104 | mem::swap(&mut small, &mut large) | ||
105 | } | ||
106 | |||
107 | let res = small | ||
108 | .iter() | ||
109 | .filter_map(|(file_id, r1)| { | ||
110 | let r2 = large.get(file_id)?; | ||
111 | let r = intersect_ranges(*r1, *r2)?; | ||
112 | Some((*file_id, r)) | ||
113 | }) | ||
114 | .collect(); | ||
115 | return SearchScope::new(res); | ||
116 | |||
117 | fn intersect_ranges( | ||
118 | r1: Option<TextRange>, | ||
119 | r2: Option<TextRange>, | ||
120 | ) -> Option<Option<TextRange>> { | ||
121 | match (r1, r2) { | ||
122 | (None, r) | (r, None) => Some(r), | ||
123 | (Some(r1), Some(r2)) => { | ||
124 | let r = r1.intersection(&r2)?; | ||
125 | Some(Some(r)) | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl IntoIterator for SearchScope { | ||
133 | type Item = (FileId, Option<TextRange>); | ||
134 | type IntoIter = std::collections::hash_map::IntoIter<FileId, Option<TextRange>>; | ||
135 | fn into_iter(self) -> Self::IntoIter { | ||
136 | self.entries.into_iter() | ||
137 | } | ||
140 | } | 138 | } |