diff options
Diffstat (limited to 'crates/ra_ide_api/src/name_kind.rs')
-rw-r--r-- | crates/ra_ide_api/src/name_kind.rs | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs deleted file mode 100644 index 583399cfe..000000000 --- a/crates/ra_ide_api/src/name_kind.rs +++ /dev/null | |||
@@ -1,287 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use hir::{ | ||
4 | db::AstDatabase, Adt, AssocItem, DefWithBody, Either, EnumVariant, FromSource, HasSource, | ||
5 | HirFileId, MacroDef, Module, ModuleDef, ModuleSource, Path, PathResolution, Source, | ||
6 | SourceAnalyzer, StructField, Ty, VariantDef, | ||
7 | }; | ||
8 | use ra_db::FileId; | ||
9 | use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; | ||
10 | |||
11 | use crate::db::RootDatabase; | ||
12 | |||
13 | #[derive(Debug, PartialEq, Eq)] | ||
14 | pub enum NameKind { | ||
15 | Macro(MacroDef), | ||
16 | FieldAccess(StructField), | ||
17 | AssocItem(AssocItem), | ||
18 | Def(ModuleDef), | ||
19 | SelfType(Ty), | ||
20 | Pat((DefWithBody, AstPtr<ast::BindPat>)), | ||
21 | SelfParam(AstPtr<ast::SelfParam>), | ||
22 | GenericParam(u32), | ||
23 | } | ||
24 | |||
25 | #[derive(PartialEq, Eq)] | ||
26 | pub(crate) struct Definition { | ||
27 | pub visibility: Option<ast::Visibility>, | ||
28 | pub container: Module, | ||
29 | pub item: NameKind, | ||
30 | } | ||
31 | |||
32 | trait HasDefinition { | ||
33 | type Def; | ||
34 | type Ref; | ||
35 | |||
36 | fn definition(self, db: &RootDatabase) -> Definition; | ||
37 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Definition>; | ||
38 | fn from_ref( | ||
39 | db: &RootDatabase, | ||
40 | analyzer: &SourceAnalyzer, | ||
41 | refer: Self::Ref, | ||
42 | ) -> Option<Definition>; | ||
43 | } | ||
44 | |||
45 | pub(crate) fn classify_name_ref( | ||
46 | db: &RootDatabase, | ||
47 | file_id: FileId, | ||
48 | analyzer: &SourceAnalyzer, | ||
49 | name_ref: &ast::NameRef, | ||
50 | ) -> Option<Definition> { | ||
51 | let parent = name_ref.syntax().parent()?; | ||
52 | match_ast! { | ||
53 | match parent { | ||
54 | ast::MethodCallExpr(it) => { | ||
55 | return AssocItem::from_ref(db, analyzer, it); | ||
56 | }, | ||
57 | ast::FieldExpr(it) => { | ||
58 | if let Some(field) = analyzer.resolve_field(&it) { | ||
59 | return Some(field.definition(db)); | ||
60 | } | ||
61 | }, | ||
62 | ast::RecordField(it) => { | ||
63 | if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { | ||
64 | let variant_def = analyzer.resolve_record_literal(&record_lit)?; | ||
65 | let hir_path = Path::from_name_ref(name_ref); | ||
66 | let hir_name = hir_path.as_ident()?; | ||
67 | let field = variant_def.field(db, hir_name)?; | ||
68 | return Some(field.definition(db)); | ||
69 | } | ||
70 | }, | ||
71 | _ => (), | ||
72 | } | ||
73 | } | ||
74 | |||
75 | let ast = ModuleSource::from_child_node(db, file_id, &parent); | ||
76 | let file_id = file_id.into(); | ||
77 | let container = Module::from_definition(db, Source { file_id, ast })?; | ||
78 | let visibility = None; | ||
79 | |||
80 | if let Some(macro_call) = | ||
81 | parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) | ||
82 | { | ||
83 | if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { | ||
84 | return Some(Definition { item: NameKind::Macro(mac), container, visibility }); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // General case, a path or a local: | ||
89 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | ||
90 | let resolved = analyzer.resolve_path(db, &path)?; | ||
91 | match resolved { | ||
92 | PathResolution::Def(def) => Some(def.definition(db)), | ||
93 | PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), | ||
94 | PathResolution::LocalBinding(Either::B(par)) => { | ||
95 | Some(Definition { item: NameKind::SelfParam(par), container, visibility }) | ||
96 | } | ||
97 | PathResolution::GenericParam(par) => { | ||
98 | // FIXME: get generic param def | ||
99 | Some(Definition { item: NameKind::GenericParam(par), container, visibility }) | ||
100 | } | ||
101 | PathResolution::Macro(def) => { | ||
102 | Some(Definition { item: NameKind::Macro(def), container, visibility }) | ||
103 | } | ||
104 | PathResolution::SelfType(impl_block) => { | ||
105 | let ty = impl_block.target_ty(db); | ||
106 | let container = impl_block.module(); | ||
107 | Some(Definition { item: NameKind::SelfType(ty), container, visibility }) | ||
108 | } | ||
109 | PathResolution::AssocItem(assoc) => Some(assoc.definition(db)), | ||
110 | } | ||
111 | } | ||
112 | |||
113 | pub(crate) fn classify_name( | ||
114 | db: &RootDatabase, | ||
115 | file_id: FileId, | ||
116 | name: &ast::Name, | ||
117 | ) -> Option<Definition> { | ||
118 | let parent = name.syntax().parent()?; | ||
119 | let file_id = file_id.into(); | ||
120 | |||
121 | match_ast! { | ||
122 | match parent { | ||
123 | ast::BindPat(it) => { | ||
124 | decl_from_pat(db, file_id, AstPtr::new(&it)) | ||
125 | }, | ||
126 | ast::RecordFieldDef(it) => { | ||
127 | StructField::from_def(db, file_id, it) | ||
128 | }, | ||
129 | ast::ImplItem(it) => { | ||
130 | AssocItem::from_def(db, file_id, it.clone()).or_else(|| { | ||
131 | match it { | ||
132 | ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), | ||
133 | ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), | ||
134 | ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), | ||
135 | } | ||
136 | }) | ||
137 | }, | ||
138 | ast::EnumVariant(it) => { | ||
139 | let src = hir::Source { file_id, ast: it.clone() }; | ||
140 | let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); | ||
141 | Some(def.definition(db)) | ||
142 | }, | ||
143 | ast::ModuleItem(it) => { | ||
144 | ModuleDef::from_def(db, file_id, it) | ||
145 | }, | ||
146 | _ => None, | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | fn decl_from_pat( | ||
152 | db: &RootDatabase, | ||
153 | file_id: HirFileId, | ||
154 | pat: AstPtr<ast::BindPat>, | ||
155 | ) -> Option<Definition> { | ||
156 | let root = db.parse_or_expand(file_id)?; | ||
157 | // FIXME: use match_ast! | ||
158 | let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { | ||
159 | if let Some(it) = ast::FnDef::cast(node.clone()) { | ||
160 | let src = hir::Source { file_id, ast: it }; | ||
161 | Some(hir::Function::from_source(db, src)?.into()) | ||
162 | } else if let Some(it) = ast::ConstDef::cast(node.clone()) { | ||
163 | let src = hir::Source { file_id, ast: it }; | ||
164 | Some(hir::Const::from_source(db, src)?.into()) | ||
165 | } else if let Some(it) = ast::StaticDef::cast(node.clone()) { | ||
166 | let src = hir::Source { file_id, ast: it }; | ||
167 | Some(hir::Static::from_source(db, src)?.into()) | ||
168 | } else { | ||
169 | None | ||
170 | } | ||
171 | })?; | ||
172 | let item = NameKind::Pat((def, pat)); | ||
173 | let container = def.module(db); | ||
174 | Some(Definition { item, container, visibility: None }) | ||
175 | } | ||
176 | |||
177 | impl HasDefinition for StructField { | ||
178 | type Def = ast::RecordFieldDef; | ||
179 | type Ref = ast::FieldExpr; | ||
180 | |||
181 | fn definition(self, db: &RootDatabase) -> Definition { | ||
182 | let item = NameKind::FieldAccess(self); | ||
183 | let parent = self.parent_def(db); | ||
184 | let container = parent.module(db); | ||
185 | let visibility = match parent { | ||
186 | VariantDef::Struct(s) => s.source(db).ast.visibility(), | ||
187 | VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), | ||
188 | }; | ||
189 | Definition { item, container, visibility } | ||
190 | } | ||
191 | |||
192 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Definition> { | ||
193 | let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; | ||
194 | let field = StructField::from_source(db, src)?; | ||
195 | Some(field.definition(db)) | ||
196 | } | ||
197 | |||
198 | fn from_ref( | ||
199 | db: &RootDatabase, | ||
200 | analyzer: &SourceAnalyzer, | ||
201 | refer: Self::Ref, | ||
202 | ) -> Option<Definition> { | ||
203 | let field = analyzer.resolve_field(&refer)?; | ||
204 | Some(field.definition(db)) | ||
205 | } | ||
206 | } | ||
207 | |||
208 | impl HasDefinition for AssocItem { | ||
209 | type Def = ast::ImplItem; | ||
210 | type Ref = ast::MethodCallExpr; | ||
211 | |||
212 | fn definition(self, db: &RootDatabase) -> Definition { | ||
213 | let item = NameKind::AssocItem(self); | ||
214 | let container = self.module(db); | ||
215 | let visibility = match self { | ||
216 | AssocItem::Function(f) => f.source(db).ast.visibility(), | ||
217 | AssocItem::Const(c) => c.source(db).ast.visibility(), | ||
218 | AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), | ||
219 | }; | ||
220 | Definition { item, container, visibility } | ||
221 | } | ||
222 | |||
223 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Definition> { | ||
224 | if def.syntax().parent().and_then(ast::ItemList::cast).is_none() { | ||
225 | return None; | ||
226 | } | ||
227 | let src = hir::Source { file_id, ast: def }; | ||
228 | let item = AssocItem::from_source(db, src)?; | ||
229 | Some(item.definition(db)) | ||
230 | } | ||
231 | |||
232 | fn from_ref( | ||
233 | db: &RootDatabase, | ||
234 | analyzer: &SourceAnalyzer, | ||
235 | refer: Self::Ref, | ||
236 | ) -> Option<Definition> { | ||
237 | let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); | ||
238 | Some(func.definition(db)) | ||
239 | } | ||
240 | } | ||
241 | |||
242 | impl HasDefinition for ModuleDef { | ||
243 | type Def = ast::ModuleItem; | ||
244 | type Ref = ast::Path; | ||
245 | |||
246 | fn definition(self, db: &RootDatabase) -> Definition { | ||
247 | let (container, visibility) = match self { | ||
248 | ModuleDef::Module(it) => { | ||
249 | let container = it.parent(db).or_else(|| Some(it)).unwrap(); | ||
250 | let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); | ||
251 | (container, visibility) | ||
252 | } | ||
253 | ModuleDef::EnumVariant(it) => { | ||
254 | let container = it.module(db); | ||
255 | let visibility = it.source(db).ast.parent_enum().visibility(); | ||
256 | (container, visibility) | ||
257 | } | ||
258 | ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()), | ||
259 | ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()), | ||
260 | ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()), | ||
261 | ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()), | ||
262 | ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()), | ||
263 | ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), | ||
264 | ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), | ||
265 | ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), | ||
266 | ModuleDef::BuiltinType(..) => unreachable!(), | ||
267 | }; | ||
268 | let item = NameKind::Def(self); | ||
269 | Definition { item, container, visibility } | ||
270 | } | ||
271 | |||
272 | fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option<Definition> { | ||
273 | let src = hir::Source { file_id, ast: def }; | ||
274 | let def = ModuleDef::from_source(db, src)?; | ||
275 | Some(def.definition(db)) | ||
276 | } | ||
277 | |||
278 | fn from_ref( | ||
279 | db: &RootDatabase, | ||
280 | analyzer: &SourceAnalyzer, | ||
281 | refer: Self::Ref, | ||
282 | ) -> Option<Definition> { | ||
283 | None | ||
284 | } | ||
285 | } | ||
286 | |||
287 | // FIXME: impl HasDefinition for hir::MacroDef | ||