diff options
author | Ekaterina Babshukova <[email protected]> | 2019-10-12 18:30:53 +0100 |
---|---|---|
committer | Ekaterina Babshukova <[email protected]> | 2019-10-22 21:47:31 +0100 |
commit | 835173d065dbe1fdd7369ea49336c0b785be8cb8 (patch) | |
tree | e19916b78f4fff145ec59b790c626e2a9f538bbb /crates/ra_ide_api/src/references/classify.rs | |
parent | d26d0ada50fd0063c03e28bc2673f9f63fd23d95 (diff) |
replace trait by a bunch of functions
Diffstat (limited to 'crates/ra_ide_api/src/references/classify.rs')
-rw-r--r-- | crates/ra_ide_api/src/references/classify.rs | 196 |
1 files changed, 111 insertions, 85 deletions
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 0b604a5cf..2ba1cf71c 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs | |||
@@ -1,47 +1,90 @@ | |||
1 | use hir::{ | 1 | use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; |
2 | AssocItem, Either, EnumVariant, FromSource, Module, ModuleDef, ModuleSource, Path, | ||
3 | PathResolution, Source, SourceAnalyzer, StructField, | ||
4 | }; | ||
5 | use ra_db::FileId; | 2 | use ra_db::FileId; |
6 | use ra_syntax::{ast, match_ast, AstNode, AstPtr}; | 3 | use ra_syntax::{ast, match_ast, AstNode, AstPtr}; |
7 | 4 | ||
8 | use super::{definition::HasDefinition, Definition, NameKind}; | 5 | use super::{ |
6 | name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field}, | ||
7 | NameDefinition, NameKind, | ||
8 | }; | ||
9 | use crate::db::RootDatabase; | 9 | use crate::db::RootDatabase; |
10 | 10 | ||
11 | use hir::{db::AstDatabase, HirFileId}; | ||
12 | |||
13 | pub(crate) fn classify_name( | 11 | pub(crate) fn classify_name( |
14 | db: &RootDatabase, | 12 | db: &RootDatabase, |
15 | file_id: FileId, | 13 | file_id: FileId, |
16 | name: &ast::Name, | 14 | name: &ast::Name, |
17 | ) -> Option<Definition> { | 15 | ) -> Option<NameDefinition> { |
18 | let parent = name.syntax().parent()?; | 16 | let parent = name.syntax().parent()?; |
19 | let file_id = file_id.into(); | 17 | let file_id = file_id.into(); |
20 | 18 | ||
19 | // FIXME: add ast::MacroCall(it) | ||
21 | match_ast! { | 20 | match_ast! { |
22 | match parent { | 21 | match parent { |
23 | ast::BindPat(it) => { | 22 | ast::BindPat(it) => { |
24 | decl_from_pat(db, file_id, AstPtr::new(&it)) | 23 | from_pat(db, file_id, AstPtr::new(&it)) |
25 | }, | 24 | }, |
26 | ast::RecordFieldDef(it) => { | 25 | ast::RecordFieldDef(it) => { |
27 | StructField::from_def(db, file_id, it) | 26 | let ast = hir::FieldSource::Named(it); |
27 | let src = hir::Source { file_id, ast }; | ||
28 | let field = hir::StructField::from_source(db, src)?; | ||
29 | Some(from_struct_field(db, field)) | ||
30 | }, | ||
31 | ast::Module(it) => { | ||
32 | let ast = hir::ModuleSource::Module(it); | ||
33 | let src = hir::Source { file_id, ast }; | ||
34 | let def = hir::Module::from_definition(db, src)?; | ||
35 | Some(from_module_def(db, def.into())) | ||
28 | }, | 36 | }, |
29 | ast::ImplItem(it) => { | 37 | ast::StructDef(it) => { |
30 | AssocItem::from_def(db, file_id, it.clone()).or_else(|| { | 38 | let src = hir::Source { file_id, ast: it }; |
31 | match it { | 39 | let def = hir::Struct::from_source(db, src)?; |
32 | ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), | 40 | Some(from_module_def(db, def.into())) |
33 | ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), | 41 | }, |
34 | ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), | 42 | ast::EnumDef(it) => { |
35 | } | 43 | let src = hir::Source { file_id, ast: it }; |
36 | }) | 44 | let def = hir::Enum::from_source(db, src)?; |
45 | Some(from_module_def(db, def.into())) | ||
46 | }, | ||
47 | ast::TraitDef(it) => { | ||
48 | let src = hir::Source { file_id, ast: it }; | ||
49 | let def = hir::Trait::from_source(db, src)?; | ||
50 | Some(from_module_def(db, def.into())) | ||
51 | }, | ||
52 | ast::StaticDef(it) => { | ||
53 | let src = hir::Source { file_id, ast: it }; | ||
54 | let def = hir::Static::from_source(db, src)?; | ||
55 | Some(from_module_def(db, def.into())) | ||
37 | }, | 56 | }, |
38 | ast::EnumVariant(it) => { | 57 | ast::EnumVariant(it) => { |
39 | let src = hir::Source { file_id, ast: it.clone() }; | 58 | let src = hir::Source { file_id, ast: it }; |
40 | let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); | 59 | let def = hir::EnumVariant::from_source(db, src)?; |
41 | Some(def.definition(db)) | 60 | Some(from_module_def(db, def.into())) |
61 | }, | ||
62 | ast::FnDef(it) => { | ||
63 | let src = hir::Source { file_id, ast: it }; | ||
64 | let def = hir::Function::from_source(db, src)?; | ||
65 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
66 | Some(from_assoc_item(db, def.into())) | ||
67 | } else { | ||
68 | Some(from_module_def(db, def.into())) | ||
69 | } | ||
70 | }, | ||
71 | ast::ConstDef(it) => { | ||
72 | let src = hir::Source { file_id, ast: it }; | ||
73 | let def = hir::Const::from_source(db, src)?; | ||
74 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
75 | Some(from_assoc_item(db, def.into())) | ||
76 | } else { | ||
77 | Some(from_module_def(db, def.into())) | ||
78 | } | ||
42 | }, | 79 | }, |
43 | ast::ModuleItem(it) => { | 80 | ast::TypeAliasDef(it) => { |
44 | ModuleDef::from_def(db, file_id, it) | 81 | let src = hir::Source { file_id, ast: it }; |
82 | let def = hir::TypeAlias::from_source(db, src)?; | ||
83 | if parent.parent().and_then(ast::ItemList::cast).is_some() { | ||
84 | Some(from_assoc_item(db, def.into())) | ||
85 | } else { | ||
86 | Some(from_module_def(db, def.into())) | ||
87 | } | ||
45 | }, | 88 | }, |
46 | _ => None, | 89 | _ => None, |
47 | } | 90 | } |
@@ -52,92 +95,75 @@ pub(crate) fn classify_name_ref( | |||
52 | db: &RootDatabase, | 95 | db: &RootDatabase, |
53 | file_id: FileId, | 96 | file_id: FileId, |
54 | name_ref: &ast::NameRef, | 97 | name_ref: &ast::NameRef, |
55 | ) -> Option<Definition> { | 98 | ) -> Option<NameDefinition> { |
56 | let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); | 99 | use PathResolution::*; |
100 | |||
57 | let parent = name_ref.syntax().parent()?; | 101 | let parent = name_ref.syntax().parent()?; |
58 | match_ast! { | 102 | let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); |
59 | match parent { | 103 | |
60 | ast::MethodCallExpr(it) => { | 104 | if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { |
61 | return AssocItem::from_ref(db, &analyzer, it); | 105 | let func = analyzer.resolve_method_call(&method_call)?; |
62 | }, | 106 | return Some(from_assoc_item(db, func.into())); |
63 | ast::FieldExpr(it) => { | 107 | } |
64 | if let Some(field) = analyzer.resolve_field(&it) { | 108 | |
65 | return Some(field.definition(db)); | 109 | if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { |
66 | } | 110 | if let Some(field) = analyzer.resolve_field(&field_expr) { |
67 | }, | 111 | return Some(from_struct_field(db, field)); |
68 | ast::RecordField(it) => { | 112 | } |
69 | if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { | 113 | } |
70 | let variant_def = analyzer.resolve_record_literal(&record_lit)?; | 114 | |
71 | let hir_path = Path::from_name_ref(name_ref); | 115 | if let Some(record_field) = ast::RecordField::cast(parent.clone()) { |
72 | let hir_name = hir_path.as_ident()?; | 116 | if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) { |
73 | let field = variant_def.field(db, hir_name)?; | 117 | let variant_def = analyzer.resolve_record_literal(&record_lit)?; |
74 | return Some(field.definition(db)); | 118 | let hir_path = Path::from_name_ref(name_ref); |
75 | } | 119 | let hir_name = hir_path.as_ident()?; |
76 | }, | 120 | let field = variant_def.field(db, hir_name)?; |
77 | _ => (), | 121 | return Some(from_struct_field(db, field)); |
78 | } | 122 | } |
79 | } | 123 | } |
80 | 124 | ||
81 | let ast = ModuleSource::from_child_node(db, file_id, &parent); | 125 | let ast = ModuleSource::from_child_node(db, file_id, &parent); |
82 | let file_id = file_id.into(); | 126 | let file_id = file_id.into(); |
127 | // FIXME: find correct container and visibility for each case | ||
83 | let container = Module::from_definition(db, Source { file_id, ast })?; | 128 | let container = Module::from_definition(db, Source { file_id, ast })?; |
84 | let visibility = None; | 129 | let visibility = None; |
85 | 130 | ||
86 | if let Some(macro_call) = | 131 | if let Some(macro_call) = |
87 | parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) | 132 | parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) |
88 | { | 133 | { |
89 | if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { | 134 | if let Some(macro_def) = analyzer.resolve_macro_call(db, ¯o_call) { |
90 | return Some(Definition { item: NameKind::Macro(mac), container, visibility }); | 135 | return Some(NameDefinition { |
136 | item: NameKind::Macro(macro_def), | ||
137 | container, | ||
138 | visibility, | ||
139 | }); | ||
91 | } | 140 | } |
92 | } | 141 | } |
93 | 142 | ||
94 | // General case, a path or a local: | ||
95 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | 143 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; |
96 | let resolved = analyzer.resolve_path(db, &path)?; | 144 | let resolved = analyzer.resolve_path(db, &path)?; |
97 | match resolved { | 145 | match resolved { |
98 | PathResolution::Def(def) => Some(def.definition(db)), | 146 | Def(def) => Some(from_module_def(db, def)), |
99 | PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), | 147 | AssocItem(item) => Some(from_assoc_item(db, item)), |
100 | PathResolution::LocalBinding(Either::B(par)) => { | 148 | LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), |
101 | Some(Definition { item: NameKind::SelfParam(par), container, visibility }) | 149 | LocalBinding(Either::B(par)) => { |
150 | let item = NameKind::SelfParam(par); | ||
151 | Some(NameDefinition { item, container, visibility }) | ||
102 | } | 152 | } |
103 | PathResolution::GenericParam(par) => { | 153 | GenericParam(par) => { |
104 | // FIXME: get generic param def | 154 | // FIXME: get generic param def |
105 | Some(Definition { item: NameKind::GenericParam(par), container, visibility }) | 155 | let item = NameKind::GenericParam(par); |
156 | Some(NameDefinition { item, container, visibility }) | ||
106 | } | 157 | } |
107 | PathResolution::Macro(def) => { | 158 | Macro(def) => { |
108 | Some(Definition { item: NameKind::Macro(def), container, visibility }) | 159 | let item = NameKind::Macro(def); |
160 | Some(NameDefinition { item, container, visibility }) | ||
109 | } | 161 | } |
110 | PathResolution::SelfType(impl_block) => { | 162 | SelfType(impl_block) => { |
111 | let ty = impl_block.target_ty(db); | 163 | let ty = impl_block.target_ty(db); |
164 | let item = NameKind::SelfType(ty); | ||
112 | let container = impl_block.module(); | 165 | let container = impl_block.module(); |
113 | Some(Definition { item: NameKind::SelfType(ty), container, visibility }) | 166 | Some(NameDefinition { item, container, visibility }) |
114 | } | 167 | } |
115 | PathResolution::AssocItem(assoc) => Some(assoc.definition(db)), | ||
116 | } | 168 | } |
117 | } | 169 | } |
118 | |||
119 | fn decl_from_pat( | ||
120 | db: &RootDatabase, | ||
121 | file_id: HirFileId, | ||
122 | pat: AstPtr<ast::BindPat>, | ||
123 | ) -> Option<Definition> { | ||
124 | let root = db.parse_or_expand(file_id)?; | ||
125 | // FIXME: use match_ast! | ||
126 | let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { | ||
127 | if let Some(it) = ast::FnDef::cast(node.clone()) { | ||
128 | let src = hir::Source { file_id, ast: it }; | ||
129 | Some(hir::Function::from_source(db, src)?.into()) | ||
130 | } else if let Some(it) = ast::ConstDef::cast(node.clone()) { | ||
131 | let src = hir::Source { file_id, ast: it }; | ||
132 | Some(hir::Const::from_source(db, src)?.into()) | ||
133 | } else if let Some(it) = ast::StaticDef::cast(node.clone()) { | ||
134 | let src = hir::Source { file_id, ast: it }; | ||
135 | Some(hir::Static::from_source(db, src)?.into()) | ||
136 | } else { | ||
137 | None | ||
138 | } | ||
139 | })?; | ||
140 | let item = NameKind::Pat((def, pat)); | ||
141 | let container = def.module(db); | ||
142 | Some(Definition { item, container, visibility: None }) | ||
143 | } | ||