diff options
author | Seivan Heidari <[email protected]> | 2019-11-21 00:11:41 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-21 00:11:41 +0000 |
commit | 358a1bcd708c622836723e5201b6de77cc9ff327 (patch) | |
tree | aeff9c96a6059fa2b02e7c87ec88753bc7993d8d /crates/ra_hir/src/from_source.rs | |
parent | 1e2d090ab8a9bda18f148b894b7948eb05b976e6 (diff) | |
parent | 612a72fc4ea4376920f2a7da7b3c334227c1716c (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_hir/src/from_source.rs')
-rw-r--r-- | crates/ra_hir/src/from_source.rs | 160 |
1 files changed, 130 insertions, 30 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 1c26756c9..b86307c58 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -4,15 +4,15 @@ use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; | |||
4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; | 4 | use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | ast::{self, AstNode, NameOwner}, | 6 | ast::{self, AstNode, NameOwner}, |
7 | match_ast, | 7 | match_ast, AstPtr, SyntaxNode, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::{AstDatabase, DefDatabase, HirDatabase}, | 11 | db::{AstDatabase, DefDatabase, HirDatabase}, |
12 | ids::{AstItemDef, LocationCtx}, | 12 | ids::{AstItemDef, LocationCtx}, |
13 | Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, | 13 | AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, |
14 | Local, MacroDef, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, | 14 | ImplBlock, Local, MacroDef, Module, ModuleDef, ModuleSource, Source, Static, Struct, |
15 | Union, VariantDef, | 15 | StructField, Trait, TypeAlias, Union, VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | pub trait FromSource: Sized { | 18 | pub trait FromSource: Sized { |
@@ -52,15 +52,54 @@ impl FromSource for Trait { | |||
52 | impl FromSource for Function { | 52 | impl FromSource for Function { |
53 | type Ast = ast::FnDef; | 53 | type Ast = ast::FnDef; |
54 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 54 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
55 | let id = from_source(db, src)?; | 55 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
56 | Some(Function { id }) | 56 | Container::Trait(it) => it.items(db), |
57 | Container::ImplBlock(it) => it.items(db), | ||
58 | Container::Module(m) => { | ||
59 | return m | ||
60 | .declarations(db) | ||
61 | .into_iter() | ||
62 | .filter_map(|it| match it { | ||
63 | ModuleDef::Function(it) => Some(it), | ||
64 | _ => None, | ||
65 | }) | ||
66 | .find(|it| same_source(&it.source(db), &src)) | ||
67 | } | ||
68 | }; | ||
69 | items | ||
70 | .into_iter() | ||
71 | .filter_map(|it| match it { | ||
72 | AssocItem::Function(it) => Some(it), | ||
73 | _ => None, | ||
74 | }) | ||
75 | .find(|it| same_source(&it.source(db), &src)) | ||
57 | } | 76 | } |
58 | } | 77 | } |
78 | |||
59 | impl FromSource for Const { | 79 | impl FromSource for Const { |
60 | type Ast = ast::ConstDef; | 80 | type Ast = ast::ConstDef; |
61 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 81 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
62 | let id = from_source(db, src)?; | 82 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
63 | Some(Const { id }) | 83 | Container::Trait(it) => it.items(db), |
84 | Container::ImplBlock(it) => it.items(db), | ||
85 | Container::Module(m) => { | ||
86 | return m | ||
87 | .declarations(db) | ||
88 | .into_iter() | ||
89 | .filter_map(|it| match it { | ||
90 | ModuleDef::Const(it) => Some(it), | ||
91 | _ => None, | ||
92 | }) | ||
93 | .find(|it| same_source(&it.source(db), &src)) | ||
94 | } | ||
95 | }; | ||
96 | items | ||
97 | .into_iter() | ||
98 | .filter_map(|it| match it { | ||
99 | AssocItem::Const(it) => Some(it), | ||
100 | _ => None, | ||
101 | }) | ||
102 | .find(|it| same_source(&it.source(db), &src)) | ||
64 | } | 103 | } |
65 | } | 104 | } |
66 | impl FromSource for Static { | 105 | impl FromSource for Static { |
@@ -73,8 +112,27 @@ impl FromSource for Static { | |||
73 | impl FromSource for TypeAlias { | 112 | impl FromSource for TypeAlias { |
74 | type Ast = ast::TypeAliasDef; | 113 | type Ast = ast::TypeAliasDef; |
75 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 114 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
76 | let id = from_source(db, src)?; | 115 | let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { |
77 | Some(TypeAlias { id }) | 116 | Container::Trait(it) => it.items(db), |
117 | Container::ImplBlock(it) => it.items(db), | ||
118 | Container::Module(m) => { | ||
119 | return m | ||
120 | .declarations(db) | ||
121 | .into_iter() | ||
122 | .filter_map(|it| match it { | ||
123 | ModuleDef::TypeAlias(it) => Some(it), | ||
124 | _ => None, | ||
125 | }) | ||
126 | .find(|it| same_source(&it.source(db), &src)) | ||
127 | } | ||
128 | }; | ||
129 | items | ||
130 | .into_iter() | ||
131 | .filter_map(|it| match it { | ||
132 | AssocItem::TypeAlias(it) => Some(it), | ||
133 | _ => None, | ||
134 | }) | ||
135 | .find(|it| same_source(&it.source(db), &src)) | ||
78 | } | 136 | } |
79 | } | 137 | } |
80 | 138 | ||
@@ -87,7 +145,7 @@ impl FromSource for MacroDef { | |||
87 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; | 145 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; |
88 | let krate = module.krate().crate_id(); | 146 | let krate = module.krate().crate_id(); |
89 | 147 | ||
90 | let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.ast)); | 148 | let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)); |
91 | 149 | ||
92 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; | 150 | let id: MacroDefId = MacroDefId { krate, ast_id, kind }; |
93 | Some(MacroDef { id }) | 151 | Some(MacroDef { id }) |
@@ -105,26 +163,26 @@ impl FromSource for ImplBlock { | |||
105 | impl FromSource for EnumVariant { | 163 | impl FromSource for EnumVariant { |
106 | type Ast = ast::EnumVariant; | 164 | type Ast = ast::EnumVariant; |
107 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 165 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
108 | let parent_enum = src.ast.parent_enum(); | 166 | let parent_enum = src.value.parent_enum(); |
109 | let src_enum = Source { file_id: src.file_id, ast: parent_enum }; | 167 | let src_enum = Source { file_id: src.file_id, value: parent_enum }; |
110 | let variants = Enum::from_source(db, src_enum)?.variants(db); | 168 | let variants = Enum::from_source(db, src_enum)?.variants(db); |
111 | variants.into_iter().find(|v| v.source(db) == src) | 169 | variants.into_iter().find(|v| same_source(&v.source(db), &src)) |
112 | } | 170 | } |
113 | } | 171 | } |
114 | 172 | ||
115 | impl FromSource for StructField { | 173 | impl FromSource for StructField { |
116 | type Ast = FieldSource; | 174 | type Ast = FieldSource; |
117 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { | 175 | fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { |
118 | let variant_def: VariantDef = match src.ast { | 176 | let variant_def: VariantDef = match src.value { |
119 | FieldSource::Named(ref field) => { | 177 | FieldSource::Named(ref field) => { |
120 | let ast = field.syntax().ancestors().find_map(ast::StructDef::cast)?; | 178 | let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; |
121 | let src = Source { file_id: src.file_id, ast }; | 179 | let src = Source { file_id: src.file_id, value }; |
122 | let def = Struct::from_source(db, src)?; | 180 | let def = Struct::from_source(db, src)?; |
123 | VariantDef::from(def) | 181 | VariantDef::from(def) |
124 | } | 182 | } |
125 | FieldSource::Pos(ref field) => { | 183 | FieldSource::Pos(ref field) => { |
126 | let ast = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; | 184 | let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; |
127 | let src = Source { file_id: src.file_id, ast }; | 185 | let src = Source { file_id: src.file_id, value }; |
128 | let def = EnumVariant::from_source(db, src)?; | 186 | let def = EnumVariant::from_source(db, src)?; |
129 | VariantDef::from(def) | 187 | VariantDef::from(def) |
130 | } | 188 | } |
@@ -142,12 +200,12 @@ impl FromSource for StructField { | |||
142 | impl Local { | 200 | impl Local { |
143 | pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { | 201 | pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { |
144 | let file_id = src.file_id; | 202 | let file_id = src.file_id; |
145 | let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| { | 203 | let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { |
146 | let res = match_ast! { | 204 | let res = match_ast! { |
147 | match it { | 205 | match it { |
148 | ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() }, | 206 | ast::ConstDef(value) => { Const::from_source(db, Source { value, file_id})?.into() }, |
149 | ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() }, | 207 | ast::StaticDef(value) => { Static::from_source(db, Source { value, file_id})?.into() }, |
150 | ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() }, | 208 | ast::FnDef(value) => { Function::from_source(db, Source { value, file_id})?.into() }, |
151 | _ => return None, | 209 | _ => return None, |
152 | } | 210 | } |
153 | }; | 211 | }; |
@@ -162,33 +220,33 @@ impl Local { | |||
162 | 220 | ||
163 | impl Module { | 221 | impl Module { |
164 | pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> { | 222 | pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> { |
165 | let parent_declaration = src.ast.syntax().ancestors().skip(1).find_map(ast::Module::cast); | 223 | let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); |
166 | 224 | ||
167 | let parent_module = match parent_declaration { | 225 | let parent_module = match parent_declaration { |
168 | Some(parent_declaration) => { | 226 | Some(parent_declaration) => { |
169 | let src_parent = Source { file_id: src.file_id, ast: parent_declaration }; | 227 | let src_parent = Source { file_id: src.file_id, value: parent_declaration }; |
170 | Module::from_declaration(db, src_parent) | 228 | Module::from_declaration(db, src_parent) |
171 | } | 229 | } |
172 | _ => { | 230 | _ => { |
173 | let src_parent = Source { | 231 | let src_parent = Source { |
174 | file_id: src.file_id, | 232 | file_id: src.file_id, |
175 | ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), | 233 | value: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), |
176 | }; | 234 | }; |
177 | Module::from_definition(db, src_parent) | 235 | Module::from_definition(db, src_parent) |
178 | } | 236 | } |
179 | }?; | 237 | }?; |
180 | 238 | ||
181 | let child_name = src.ast.name()?; | 239 | let child_name = src.value.name()?; |
182 | parent_module.child(db, &child_name.as_name()) | 240 | parent_module.child(db, &child_name.as_name()) |
183 | } | 241 | } |
184 | 242 | ||
185 | pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> { | 243 | pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> { |
186 | match src.ast { | 244 | match src.value { |
187 | ModuleSource::Module(ref module) => { | 245 | ModuleSource::Module(ref module) => { |
188 | assert!(!module.has_semi()); | 246 | assert!(!module.has_semi()); |
189 | return Module::from_declaration( | 247 | return Module::from_declaration( |
190 | db, | 248 | db, |
191 | Source { file_id: src.file_id, ast: module.clone() }, | 249 | Source { file_id: src.file_id, value: module.clone() }, |
192 | ); | 250 | ); |
193 | } | 251 | } |
194 | ModuleSource::SourceFile(_) => (), | 252 | ModuleSource::SourceFile(_) => (), |
@@ -214,5 +272,47 @@ where | |||
214 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); | 272 | let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); |
215 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; | 273 | let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; |
216 | let ctx = LocationCtx::new(db, module.id, src.file_id); | 274 | let ctx = LocationCtx::new(db, module.id, src.file_id); |
217 | Some(DEF::from_ast(ctx, &src.ast)) | 275 | Some(DEF::from_ast(ctx, &src.value)) |
276 | } | ||
277 | |||
278 | enum Container { | ||
279 | Trait(Trait), | ||
280 | ImplBlock(ImplBlock), | ||
281 | Module(Module), | ||
282 | } | ||
283 | |||
284 | impl Container { | ||
285 | fn find(db: &impl DefDatabase, src: Source<&SyntaxNode>) -> Option<Container> { | ||
286 | // FIXME: this doesn't try to handle nested declarations | ||
287 | for container in src.value.ancestors() { | ||
288 | let res = match_ast! { | ||
289 | match container { | ||
290 | ast::TraitDef(it) => { | ||
291 | let c = Trait::from_source(db, src.with_value(it))?; | ||
292 | Container::Trait(c) | ||
293 | }, | ||
294 | ast::ImplBlock(it) => { | ||
295 | let c = ImplBlock::from_source(db, src.with_value(it))?; | ||
296 | Container::ImplBlock(c) | ||
297 | }, | ||
298 | _ => { continue }, | ||
299 | } | ||
300 | }; | ||
301 | return Some(res); | ||
302 | } | ||
303 | |||
304 | let module_source = ModuleSource::from_child_node(db, src); | ||
305 | let c = Module::from_definition(db, src.with_value(module_source))?; | ||
306 | Some(Container::Module(c)) | ||
307 | } | ||
308 | } | ||
309 | |||
310 | /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are | ||
311 | /// equal if they point to exactly the same object. | ||
312 | /// | ||
313 | /// In general, we do not guarantee that we have exactly one instance of a | ||
314 | /// syntax tree for each file. We probably should add such guarantee, but, for | ||
315 | /// the time being, we will use identity-less AstPtr comparison. | ||
316 | fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool { | ||
317 | s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) | ||
218 | } | 318 | } |