aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/from_source.rs
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-21 00:11:41 +0000
committerSeivan Heidari <[email protected]>2019-11-21 00:11:41 +0000
commit358a1bcd708c622836723e5201b6de77cc9ff327 (patch)
treeaeff9c96a6059fa2b02e7c87ec88753bc7993d8d /crates/ra_hir/src/from_source.rs
parent1e2d090ab8a9bda18f148b894b7948eb05b976e6 (diff)
parent612a72fc4ea4376920f2a7da7b3c334227c1716c (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.rs160
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};
4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
5use ra_syntax::{ 5use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 6 ast::{self, AstNode, NameOwner},
7 match_ast, 7 match_ast, AstPtr, SyntaxNode,
8}; 8};
9 9
10use crate::{ 10use 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
18pub trait FromSource: Sized { 18pub trait FromSource: Sized {
@@ -52,15 +52,54 @@ impl FromSource for Trait {
52impl FromSource for Function { 52impl 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
59impl FromSource for Const { 79impl 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}
66impl FromSource for Static { 105impl FromSource for Static {
@@ -73,8 +112,27 @@ impl FromSource for Static {
73impl FromSource for TypeAlias { 112impl 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 {
105impl FromSource for EnumVariant { 163impl 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
115impl FromSource for StructField { 173impl 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 {
142impl Local { 200impl 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
163impl Module { 221impl 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
278enum Container {
279 Trait(Trait),
280 ImplBlock(ImplBlock),
281 Module(Module),
282}
283
284impl 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.
316fn 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}