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/src/defs.rs196
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs75
-rw-r--r--crates/ra_ide_db/src/lib.rs2
3 files changed, 273 insertions, 0 deletions
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
new file mode 100644
index 000000000..cee6dde8e
--- /dev/null
+++ b/crates/ra_ide_db/src/defs.rs
@@ -0,0 +1,196 @@
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// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
7
8use hir::{
9 Adt, AssocItem, HasSource, ImplBlock, InFile, Local, MacroDef, Module, ModuleDef, SourceBinder,
10 StructField, TypeParam, VariantDef,
11};
12use ra_prof::profile;
13use ra_syntax::{
14 ast::{self, AstNode, VisibilityOwner},
15 match_ast,
16};
17
18use crate::RootDatabase;
19
20#[derive(Debug, PartialEq, Eq)]
21pub enum NameKind {
22 Macro(MacroDef),
23 Field(StructField),
24 AssocItem(AssocItem),
25 Def(ModuleDef),
26 SelfType(ImplBlock),
27 Local(Local),
28 TypeParam(TypeParam),
29}
30
31#[derive(PartialEq, Eq)]
32pub struct NameDefinition {
33 pub visibility: Option<ast::Visibility>,
34 /// FIXME: this doesn't really make sense. For example, builtin types don't
35 /// really have a module.
36 pub container: Module,
37 pub kind: NameKind,
38}
39
40pub fn classify_name(
41 sb: &mut SourceBinder<RootDatabase>,
42 name: InFile<&ast::Name>,
43) -> Option<NameDefinition> {
44 let _p = profile("classify_name");
45 let parent = name.value.syntax().parent()?;
46
47 match_ast! {
48 match parent {
49 ast::BindPat(it) => {
50 let src = name.with_value(it);
51 let local = sb.to_def(src)?;
52 Some(NameDefinition {
53 visibility: None,
54 container: local.module(sb.db),
55 kind: NameKind::Local(local),
56 })
57 },
58 ast::RecordFieldDef(it) => {
59 let src = name.with_value(it);
60 let field: hir::StructField = sb.to_def(src)?;
61 Some(from_struct_field(sb.db, field))
62 },
63 ast::Module(it) => {
64 let def = sb.to_def(name.with_value(it))?;
65 Some(from_module_def(sb.db, def.into(), None))
66 },
67 ast::StructDef(it) => {
68 let src = name.with_value(it);
69 let def: hir::Struct = sb.to_def(src)?;
70 Some(from_module_def(sb.db, def.into(), None))
71 },
72 ast::EnumDef(it) => {
73 let src = name.with_value(it);
74 let def: hir::Enum = sb.to_def(src)?;
75 Some(from_module_def(sb.db, def.into(), None))
76 },
77 ast::TraitDef(it) => {
78 let src = name.with_value(it);
79 let def: hir::Trait = sb.to_def(src)?;
80 Some(from_module_def(sb.db, def.into(), None))
81 },
82 ast::StaticDef(it) => {
83 let src = name.with_value(it);
84 let def: hir::Static = sb.to_def(src)?;
85 Some(from_module_def(sb.db, def.into(), None))
86 },
87 ast::EnumVariant(it) => {
88 let src = name.with_value(it);
89 let def: hir::EnumVariant = sb.to_def(src)?;
90 Some(from_module_def(sb.db, def.into(), None))
91 },
92 ast::FnDef(it) => {
93 let src = name.with_value(it);
94 let def: hir::Function = sb.to_def(src)?;
95 if parent.parent().and_then(ast::ItemList::cast).is_some() {
96 Some(from_assoc_item(sb.db, def.into()))
97 } else {
98 Some(from_module_def(sb.db, def.into(), None))
99 }
100 },
101 ast::ConstDef(it) => {
102 let src = name.with_value(it);
103 let def: hir::Const = sb.to_def(src)?;
104 if parent.parent().and_then(ast::ItemList::cast).is_some() {
105 Some(from_assoc_item(sb.db, def.into()))
106 } else {
107 Some(from_module_def(sb.db, def.into(), None))
108 }
109 },
110 ast::TypeAliasDef(it) => {
111 let src = name.with_value(it);
112 let def: hir::TypeAlias = sb.to_def(src)?;
113 if parent.parent().and_then(ast::ItemList::cast).is_some() {
114 Some(from_assoc_item(sb.db, def.into()))
115 } else {
116 Some(from_module_def(sb.db, def.into(), None))
117 }
118 },
119 ast::MacroCall(it) => {
120 let src = name.with_value(it);
121 let def = sb.to_def(src.clone())?;
122
123 let module = sb.to_module_def(src.file_id.original_file(sb.db))?;
124
125 Some(NameDefinition {
126 visibility: None,
127 container: module,
128 kind: NameKind::Macro(def),
129 })
130 },
131 ast::TypeParam(it) => {
132 let src = name.with_value(it);
133 let def = sb.to_def(src)?;
134 Some(NameDefinition {
135 visibility: None,
136 container: def.module(sb.db),
137 kind: NameKind::TypeParam(def),
138 })
139 },
140 _ => None,
141 }
142 }
143}
144
145pub fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
146 let container = item.module(db);
147 let visibility = match item {
148 AssocItem::Function(f) => f.source(db).value.visibility(),
149 AssocItem::Const(c) => c.source(db).value.visibility(),
150 AssocItem::TypeAlias(a) => a.source(db).value.visibility(),
151 };
152 let kind = NameKind::AssocItem(item);
153 NameDefinition { kind, container, visibility }
154}
155
156pub fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition {
157 let kind = NameKind::Field(field);
158 let parent = field.parent_def(db);
159 let container = parent.module(db);
160 let visibility = match parent {
161 VariantDef::Struct(s) => s.source(db).value.visibility(),
162 VariantDef::Union(e) => e.source(db).value.visibility(),
163 VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(),
164 };
165 NameDefinition { kind, container, visibility }
166}
167
168pub fn from_module_def(
169 db: &RootDatabase,
170 def: ModuleDef,
171 module: Option<Module>,
172) -> NameDefinition {
173 let kind = NameKind::Def(def);
174 let (container, visibility) = match def {
175 ModuleDef::Module(it) => {
176 let container = it.parent(db).or_else(|| Some(it)).unwrap();
177 let visibility = it.declaration_source(db).and_then(|s| s.value.visibility());
178 (container, visibility)
179 }
180 ModuleDef::EnumVariant(it) => {
181 let container = it.module(db);
182 let visibility = it.source(db).value.parent_enum().visibility();
183 (container, visibility)
184 }
185 ModuleDef::Function(it) => (it.module(db), it.source(db).value.visibility()),
186 ModuleDef::Const(it) => (it.module(db), it.source(db).value.visibility()),
187 ModuleDef::Static(it) => (it.module(db), it.source(db).value.visibility()),
188 ModuleDef::Trait(it) => (it.module(db), it.source(db).value.visibility()),
189 ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).value.visibility()),
190 ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).value.visibility()),
191 ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).value.visibility()),
192 ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).value.visibility()),
193 ModuleDef::BuiltinType(..) => (module.unwrap(), None),
194 };
195 NameDefinition { kind, container, visibility }
196}
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
new file mode 100644
index 000000000..21e637608
--- /dev/null
+++ b/crates/ra_ide_db/src/imports_locator.rs
@@ -0,0 +1,75 @@
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.
3
4use hir::{db::HirDatabase, ModuleDef, SourceBinder};
5use ra_assists::ImportsLocator;
6use ra_prof::profile;
7use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
8
9use crate::{
10 defs::classify_name,
11 defs::NameKind,
12 symbol_index::{self, FileSymbol, Query},
13 RootDatabase,
14};
15
16pub struct ImportsLocatorIde<'a> {
17 source_binder: SourceBinder<'a, RootDatabase>,
18}
19
20impl<'a> ImportsLocatorIde<'a> {
21 pub fn new(db: &'a RootDatabase) -> Self {
22 Self { source_binder: SourceBinder::new(db) }
23 }
24
25 fn get_name_definition(
26 &mut self,
27 db: &impl HirDatabase,
28 import_candidate: &FileSymbol,
29 ) -> Option<NameKind> {
30 let _p = profile("get_name_definition");
31 let file_id = import_candidate.file_id.into();
32 let candidate_node = import_candidate.ptr.to_node(&db.parse_or_expand(file_id)?);
33 let candidate_name_node = if candidate_node.kind() != NAME {
34 candidate_node.children().find(|it| it.kind() == NAME)?
35 } else {
36 candidate_node
37 };
38 classify_name(
39 &mut self.source_binder,
40 hir::InFile { file_id, value: &ast::Name::cast(candidate_name_node)? },
41 )
42 .map(|it| it.kind)
43 }
44}
45
46impl ImportsLocator for ImportsLocatorIde<'_> {
47 fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
48 let _p = profile("search_for_imports");
49 let db = self.source_binder.db;
50
51 let project_results = {
52 let mut query = Query::new(name_to_import.to_string());
53 query.exact();
54 query.limit(40);
55 symbol_index::world_symbols(db, query)
56 };
57 let lib_results = {
58 let mut query = Query::new(name_to_import.to_string());
59 query.libs();
60 query.exact();
61 query.limit(40);
62 symbol_index::world_symbols(db, query)
63 };
64
65 project_results
66 .into_iter()
67 .chain(lib_results.into_iter())
68 .filter_map(|import_candidate| self.get_name_definition(db, &import_candidate))
69 .filter_map(|name_definition_to_import| match name_definition_to_import {
70 NameKind::Def(module_def) => Some(module_def),
71 _ => None,
72 })
73 .collect()
74 }
75}
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index e922d1e5f..877ac3c38 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -7,6 +7,8 @@ pub mod line_index_utils;
7pub mod feature_flags; 7pub mod feature_flags;
8pub mod symbol_index; 8pub mod symbol_index;
9pub mod change; 9pub mod change;
10pub mod defs;
11pub mod imports_locator;
10mod wasm_shims; 12mod wasm_shims;
11 13
12use std::sync::Arc; 14use std::sync::Arc;