aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/from_source.rs147
1 files changed, 48 insertions, 99 deletions
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 18d87f6d7..6fa947759 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,17 +1,20 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2use either::Either;
2 3
3use hir_def::{nameres::ModuleSource, AstItemDef, LocationCtx, ModuleId}; 4use hir_def::{
5 child_from_source::ChildFromSource, nameres::ModuleSource, AstItemDef, EnumVariantId, ImplId,
6 LocationCtx, ModuleId, TraitId, VariantId,
7};
4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 8use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
5use ra_syntax::{ 9use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 10 ast::{self, AstNode, NameOwner},
7 match_ast, AstPtr, SyntaxNode, 11 match_ast, SyntaxNode,
8}; 12};
9 13
10use crate::{ 14use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 15 db::{AstDatabase, DefDatabase, HirDatabase},
12 AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, 16 Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local,
13 InFile, Local, MacroDef, Module, ModuleDef, Static, Struct, StructField, Trait, TypeAlias, 17 MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, Union,
14 Union, VariantDef,
15}; 18};
16 19
17pub trait FromSource: Sized { 20pub trait FromSource: Sized {
@@ -50,98 +53,36 @@ impl FromSource for Trait {
50impl FromSource for Function { 53impl FromSource for Function {
51 type Ast = ast::FnDef; 54 type Ast = ast::FnDef;
52 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 55 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
53 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 56 Container::find(db, src.as_ref().map(|it| it.syntax()))?
54 Container::Trait(it) => it.items(db), 57 .child_from_source(db, src)
55 Container::ImplBlock(it) => it.items(db), 58 .map(Function::from)
56 Container::Module(m) => {
57 return m
58 .declarations(db)
59 .into_iter()
60 .filter_map(|it| match it {
61 ModuleDef::Function(it) => Some(it),
62 _ => None,
63 })
64 .find(|it| same_source(&it.source(db), &src))
65 }
66 };
67 items
68 .into_iter()
69 .filter_map(|it| match it {
70 AssocItem::Function(it) => Some(it),
71 _ => None,
72 })
73 .find(|it| same_source(&it.source(db), &src))
74 } 59 }
75} 60}
76 61
77impl FromSource for Const { 62impl FromSource for Const {
78 type Ast = ast::ConstDef; 63 type Ast = ast::ConstDef;
79 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 64 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
80 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 65 Container::find(db, src.as_ref().map(|it| it.syntax()))?
81 Container::Trait(it) => it.items(db), 66 .child_from_source(db, src)
82 Container::ImplBlock(it) => it.items(db), 67 .map(Const::from)
83 Container::Module(m) => {
84 return m
85 .declarations(db)
86 .into_iter()
87 .filter_map(|it| match it {
88 ModuleDef::Const(it) => Some(it),
89 _ => None,
90 })
91 .find(|it| same_source(&it.source(db), &src))
92 }
93 };
94 items
95 .into_iter()
96 .filter_map(|it| match it {
97 AssocItem::Const(it) => Some(it),
98 _ => None,
99 })
100 .find(|it| same_source(&it.source(db), &src))
101 } 68 }
102} 69}
103impl FromSource for Static { 70impl FromSource for Static {
104 type Ast = ast::StaticDef; 71 type Ast = ast::StaticDef;
105 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 72 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
106 let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 73 match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
107 Container::Module(it) => it, 74 Container::Module(it) => it.id.child_from_source(db, src).map(Static::from),
108 Container::Trait(_) | Container::ImplBlock(_) => return None, 75 Container::Trait(_) | Container::ImplBlock(_) => None,
109 }; 76 }
110 module
111 .declarations(db)
112 .into_iter()
113 .filter_map(|it| match it {
114 ModuleDef::Static(it) => Some(it),
115 _ => None,
116 })
117 .find(|it| same_source(&it.source(db), &src))
118 } 77 }
119} 78}
120 79
121impl FromSource for TypeAlias { 80impl FromSource for TypeAlias {
122 type Ast = ast::TypeAliasDef; 81 type Ast = ast::TypeAliasDef;
123 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 82 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
124 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 83 Container::find(db, src.as_ref().map(|it| it.syntax()))?
125 Container::Trait(it) => it.items(db), 84 .child_from_source(db, src)
126 Container::ImplBlock(it) => it.items(db), 85 .map(TypeAlias::from)
127 Container::Module(m) => {
128 return m
129 .declarations(db)
130 .into_iter()
131 .filter_map(|it| match it {
132 ModuleDef::TypeAlias(it) => Some(it),
133 _ => None,
134 })
135 .find(|it| same_source(&it.source(db), &src))
136 }
137 };
138 items
139 .into_iter()
140 .filter_map(|it| match it {
141 AssocItem::TypeAlias(it) => Some(it),
142 _ => None,
143 })
144 .find(|it| same_source(&it.source(db), &src))
145 } 86 }
146} 87}
147 88
@@ -174,34 +115,33 @@ impl FromSource for EnumVariant {
174 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 115 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
175 let parent_enum = src.value.parent_enum(); 116 let parent_enum = src.value.parent_enum();
176 let src_enum = InFile { file_id: src.file_id, value: parent_enum }; 117 let src_enum = InFile { file_id: src.file_id, value: parent_enum };
177 let variants = Enum::from_source(db, src_enum)?.variants(db); 118 let parent_enum = Enum::from_source(db, src_enum)?;
178 variants.into_iter().find(|v| same_source(&v.source(db), &src)) 119 parent_enum.id.child_from_source(db, src).map(EnumVariant::from)
179 } 120 }
180} 121}
181 122
182impl FromSource for StructField { 123impl FromSource for StructField {
183 type Ast = FieldSource; 124 type Ast = FieldSource;
184 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> { 125 fn from_source(db: &(impl DefDatabase + AstDatabase), src: InFile<Self::Ast>) -> Option<Self> {
185 let variant_def: VariantDef = match src.value { 126 let variant_id: VariantId = match src.value {
186 FieldSource::Named(ref field) => { 127 FieldSource::Named(ref field) => {
187 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; 128 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
188 let src = InFile { file_id: src.file_id, value }; 129 let src = InFile { file_id: src.file_id, value };
189 let def = Struct::from_source(db, src)?; 130 let def = Struct::from_source(db, src)?;
190 VariantDef::from(def) 131 def.id.into()
191 } 132 }
192 FieldSource::Pos(ref field) => { 133 FieldSource::Pos(ref field) => {
193 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; 134 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
194 let src = InFile { file_id: src.file_id, value }; 135 let src = InFile { file_id: src.file_id, value };
195 let def = EnumVariant::from_source(db, src)?; 136 let def = EnumVariant::from_source(db, src)?;
196 VariantDef::from(def) 137 EnumVariantId::from(def).into()
197 } 138 }
198 }; 139 };
199 variant_def 140 let src = src.map(|field_source| match field_source {
200 .variant_data(db) 141 FieldSource::Pos(it) => Either::Left(it),
201 .fields() 142 FieldSource::Named(it) => Either::Right(it),
202 .iter() 143 });
203 .map(|(id, _)| StructField { parent: variant_def, id }) 144 variant_id.child_from_source(db, src).map(StructField::from)
204 .find(|f| f.source(db) == src)
205 } 145 }
206} 146}
207 147
@@ -315,12 +255,21 @@ impl Container {
315 } 255 }
316} 256}
317 257
318/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are 258impl<CHILD, SOURCE> ChildFromSource<CHILD, SOURCE> for Container
319/// equal if they point to exactly the same object. 259where
320/// 260 TraitId: ChildFromSource<CHILD, SOURCE>,
321/// In general, we do not guarantee that we have exactly one instance of a 261 ImplId: ChildFromSource<CHILD, SOURCE>,
322/// syntax tree for each file. We probably should add such guarantee, but, for 262 ModuleId: ChildFromSource<CHILD, SOURCE>,
323/// the time being, we will use identity-less AstPtr comparison. 263{
324fn same_source<N: AstNode>(s1: &InFile<N>, s2: &InFile<N>) -> bool { 264 fn child_from_source(
325 s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) 265 &self,
266 db: &impl DefDatabase,
267 child_source: InFile<SOURCE>,
268 ) -> Option<CHILD> {
269 match self {
270 Container::Trait(it) => it.id.child_from_source(db, child_source),
271 Container::ImplBlock(it) => it.id.child_from_source(db, child_source),
272 Container::Module(it) => it.id.child_from_source(db, child_source),
273 }
274 }
326} 275}