aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_db/src/defs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_db/src/defs.rs')
-rw-r--r--crates/ra_ide_db/src/defs.rs194
1 files changed, 194 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..1c983fb60
--- /dev/null
+++ b/crates/ra_ide_db/src/defs.rs
@@ -0,0 +1,194 @@
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
6use hir::{
7 Adt, AssocItem, HasSource, ImplBlock, InFile, Local, MacroDef, Module, ModuleDef, SourceBinder,
8 StructField, TypeParam, VariantDef,
9};
10use ra_prof::profile;
11use ra_syntax::{
12 ast::{self, AstNode, VisibilityOwner},
13 match_ast,
14};
15
16use crate::RootDatabase;
17
18#[derive(Debug, PartialEq, Eq)]
19pub enum NameKind {
20 Macro(MacroDef),
21 Field(StructField),
22 AssocItem(AssocItem),
23 Def(ModuleDef),
24 SelfType(ImplBlock),
25 Local(Local),
26 TypeParam(TypeParam),
27}
28
29#[derive(PartialEq, Eq)]
30pub struct NameDefinition {
31 pub visibility: Option<ast::Visibility>,
32 /// FIXME: this doesn't really make sense. For example, builtin types don't
33 /// really have a module.
34 pub container: Module,
35 pub kind: NameKind,
36}
37
38pub fn classify_name(
39 sb: &mut SourceBinder<RootDatabase>,
40 name: InFile<&ast::Name>,
41) -> Option<NameDefinition> {
42 let _p = profile("classify_name");
43 let parent = name.value.syntax().parent()?;
44
45 match_ast! {
46 match parent {
47 ast::BindPat(it) => {
48 let src = name.with_value(it);
49 let local = sb.to_def(src)?;
50 Some(NameDefinition {
51 visibility: None,
52 container: local.module(sb.db),
53 kind: NameKind::Local(local),
54 })
55 },
56 ast::RecordFieldDef(it) => {
57 let src = name.with_value(it);
58 let field: hir::StructField = sb.to_def(src)?;
59 Some(from_struct_field(sb.db, field))
60 },
61 ast::Module(it) => {
62 let def = sb.to_def(name.with_value(it))?;
63 Some(from_module_def(sb.db, def.into(), None))
64 },
65 ast::StructDef(it) => {
66 let src = name.with_value(it);
67 let def: hir::Struct = sb.to_def(src)?;
68 Some(from_module_def(sb.db, def.into(), None))
69 },
70 ast::EnumDef(it) => {
71 let src = name.with_value(it);
72 let def: hir::Enum = sb.to_def(src)?;
73 Some(from_module_def(sb.db, def.into(), None))
74 },
75 ast::TraitDef(it) => {
76 let src = name.with_value(it);
77 let def: hir::Trait = sb.to_def(src)?;
78 Some(from_module_def(sb.db, def.into(), None))
79 },
80 ast::StaticDef(it) => {
81 let src = name.with_value(it);
82 let def: hir::Static = sb.to_def(src)?;
83 Some(from_module_def(sb.db, def.into(), None))
84 },
85 ast::EnumVariant(it) => {
86 let src = name.with_value(it);
87 let def: hir::EnumVariant = sb.to_def(src)?;
88 Some(from_module_def(sb.db, def.into(), None))
89 },
90 ast::FnDef(it) => {
91 let src = name.with_value(it);
92 let def: hir::Function = sb.to_def(src)?;
93 if parent.parent().and_then(ast::ItemList::cast).is_some() {
94 Some(from_assoc_item(sb.db, def.into()))
95 } else {
96 Some(from_module_def(sb.db, def.into(), None))
97 }
98 },
99 ast::ConstDef(it) => {
100 let src = name.with_value(it);
101 let def: hir::Const = sb.to_def(src)?;
102 if parent.parent().and_then(ast::ItemList::cast).is_some() {
103 Some(from_assoc_item(sb.db, def.into()))
104 } else {
105 Some(from_module_def(sb.db, def.into(), None))
106 }
107 },
108 ast::TypeAliasDef(it) => {
109 let src = name.with_value(it);
110 let def: hir::TypeAlias = sb.to_def(src)?;
111 if parent.parent().and_then(ast::ItemList::cast).is_some() {
112 Some(from_assoc_item(sb.db, def.into()))
113 } else {
114 Some(from_module_def(sb.db, def.into(), None))
115 }
116 },
117 ast::MacroCall(it) => {
118 let src = name.with_value(it);
119 let def = sb.to_def(src.clone())?;
120
121 let module = sb.to_module_def(src.file_id.original_file(sb.db))?;
122
123 Some(NameDefinition {
124 visibility: None,
125 container: module,
126 kind: NameKind::Macro(def),
127 })
128 },
129 ast::TypeParam(it) => {
130 let src = name.with_value(it);
131 let def = sb.to_def(src)?;
132 Some(NameDefinition {
133 visibility: None,
134 container: def.module(sb.db),
135 kind: NameKind::TypeParam(def),
136 })
137 },
138 _ => None,
139 }
140 }
141}
142
143pub fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
144 let container = item.module(db);
145 let visibility = match item {
146 AssocItem::Function(f) => f.source(db).value.visibility(),
147 AssocItem::Const(c) => c.source(db).value.visibility(),
148 AssocItem::TypeAlias(a) => a.source(db).value.visibility(),
149 };
150 let kind = NameKind::AssocItem(item);
151 NameDefinition { kind, container, visibility }
152}
153
154pub fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition {
155 let kind = NameKind::Field(field);
156 let parent = field.parent_def(db);
157 let container = parent.module(db);
158 let visibility = match parent {
159 VariantDef::Struct(s) => s.source(db).value.visibility(),
160 VariantDef::Union(e) => e.source(db).value.visibility(),
161 VariantDef::EnumVariant(e) => e.source(db).value.parent_enum().visibility(),
162 };
163 NameDefinition { kind, container, visibility }
164}
165
166pub fn from_module_def(
167 db: &RootDatabase,
168 def: ModuleDef,
169 module: Option<Module>,
170) -> NameDefinition {
171 let kind = NameKind::Def(def);
172 let (container, visibility) = match def {
173 ModuleDef::Module(it) => {
174 let container = it.parent(db).or_else(|| Some(it)).unwrap();
175 let visibility = it.declaration_source(db).and_then(|s| s.value.visibility());
176 (container, visibility)
177 }
178 ModuleDef::EnumVariant(it) => {
179 let container = it.module(db);
180 let visibility = it.source(db).value.parent_enum().visibility();
181 (container, visibility)
182 }
183 ModuleDef::Function(it) => (it.module(db), it.source(db).value.visibility()),
184 ModuleDef::Const(it) => (it.module(db), it.source(db).value.visibility()),
185 ModuleDef::Static(it) => (it.module(db), it.source(db).value.visibility()),
186 ModuleDef::Trait(it) => (it.module(db), it.source(db).value.visibility()),
187 ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).value.visibility()),
188 ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).value.visibility()),
189 ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).value.visibility()),
190 ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).value.visibility()),
191 ModuleDef::BuiltinType(..) => (module.unwrap(), None),
192 };
193 NameDefinition { kind, container, visibility }
194}