diff options
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 83 |
1 files changed, 48 insertions, 35 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 66cb4b357..ca40e3b54 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -7,8 +7,11 @@ | |||
7 | //! purely for "IDE needs". | 7 | //! purely for "IDE needs". |
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use hir_def::path::known; | 10 | use hir_def::{ |
11 | use hir_expand::name::AsName; | 11 | expr::{ExprId, PatId}, |
12 | path::known, | ||
13 | }; | ||
14 | use hir_expand::{name::AsName, Source}; | ||
12 | use ra_db::FileId; | 15 | use ra_db::FileId; |
13 | use ra_syntax::{ | 16 | use ra_syntax::{ |
14 | ast::{self, AstNode}, | 17 | ast::{self, AstNode}, |
@@ -20,16 +23,12 @@ use rustc_hash::FxHashSet; | |||
20 | 23 | ||
21 | use crate::{ | 24 | use crate::{ |
22 | db::HirDatabase, | 25 | db::HirDatabase, |
23 | expr::{ | 26 | expr::{self, BodySourceMap, ExprScopes, ScopeId}, |
24 | self, | ||
25 | scope::{ExprScopes, ScopeId}, | ||
26 | BodySourceMap, | ||
27 | }, | ||
28 | ids::LocationCtx, | 27 | ids::LocationCtx, |
29 | resolve::{ScopeDef, TypeNs, ValueNs}, | 28 | resolve::{ScopeDef, TypeNs, ValueNs}, |
30 | ty::method_resolution::{self, implements_trait}, | 29 | ty::method_resolution::{self, implements_trait}, |
31 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, | 30 | AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, GenericParam, HasBody, |
32 | MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, | 31 | HirFileId, Local, MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty, |
33 | }; | 32 | }; |
34 | 33 | ||
35 | fn try_get_resolver_for_node( | 34 | fn try_get_resolver_for_node( |
@@ -93,7 +92,10 @@ fn def_with_body_from_child_node( | |||
93 | /// original source files. It should not be used inside the HIR itself. | 92 | /// original source files. It should not be used inside the HIR itself. |
94 | #[derive(Debug)] | 93 | #[derive(Debug)] |
95 | pub struct SourceAnalyzer { | 94 | pub struct SourceAnalyzer { |
95 | // FIXME: this doesn't handle macros at all | ||
96 | file_id: FileId, | ||
96 | resolver: Resolver, | 97 | resolver: Resolver, |
98 | body_owner: Option<DefWithBody>, | ||
97 | body_source_map: Option<Arc<BodySourceMap>>, | 99 | body_source_map: Option<Arc<BodySourceMap>>, |
98 | infer: Option<Arc<crate::ty::InferenceResult>>, | 100 | infer: Option<Arc<crate::ty::InferenceResult>>, |
99 | scopes: Option<Arc<crate::expr::ExprScopes>>, | 101 | scopes: Option<Arc<crate::expr::ExprScopes>>, |
@@ -104,9 +106,9 @@ pub enum PathResolution { | |||
104 | /// An item | 106 | /// An item |
105 | Def(crate::ModuleDef), | 107 | Def(crate::ModuleDef), |
106 | /// A local binding (only value namespace) | 108 | /// A local binding (only value namespace) |
107 | LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>), | 109 | Local(Local), |
108 | /// A generic parameter | 110 | /// A generic parameter |
109 | GenericParam(u32), | 111 | GenericParam(GenericParam), |
110 | SelfType(crate::ImplBlock), | 112 | SelfType(crate::ImplBlock), |
111 | Macro(MacroDef), | 113 | Macro(MacroDef), |
112 | AssocItem(crate::AssocItem), | 114 | AssocItem(crate::AssocItem), |
@@ -144,17 +146,19 @@ impl SourceAnalyzer { | |||
144 | let def_with_body = def_with_body_from_child_node(db, file_id, node); | 146 | let def_with_body = def_with_body_from_child_node(db, file_id, node); |
145 | if let Some(def) = def_with_body { | 147 | if let Some(def) = def_with_body { |
146 | let source_map = def.body_source_map(db); | 148 | let source_map = def.body_source_map(db); |
147 | let scopes = db.expr_scopes(def); | 149 | let scopes = def.expr_scopes(db); |
148 | let scope = match offset { | 150 | let scope = match offset { |
149 | None => scope_for(&scopes, &source_map, &node), | 151 | None => scope_for(&scopes, &source_map, file_id.into(), &node), |
150 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), | 152 | Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), |
151 | }; | 153 | }; |
152 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | 154 | let resolver = expr::resolver_for_scope(db, def, scope); |
153 | SourceAnalyzer { | 155 | SourceAnalyzer { |
154 | resolver, | 156 | resolver, |
157 | body_owner: Some(def), | ||
155 | body_source_map: Some(source_map), | 158 | body_source_map: Some(source_map), |
156 | infer: Some(def.infer(db)), | 159 | infer: Some(def.infer(db)), |
157 | scopes: Some(scopes), | 160 | scopes: Some(scopes), |
161 | file_id, | ||
158 | } | 162 | } |
159 | } else { | 163 | } else { |
160 | SourceAnalyzer { | 164 | SourceAnalyzer { |
@@ -162,20 +166,32 @@ impl SourceAnalyzer { | |||
162 | .ancestors() | 166 | .ancestors() |
163 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) | 167 | .find_map(|node| try_get_resolver_for_node(db, file_id, &node)) |
164 | .unwrap_or_default(), | 168 | .unwrap_or_default(), |
169 | body_owner: None, | ||
165 | body_source_map: None, | 170 | body_source_map: None, |
166 | infer: None, | 171 | infer: None, |
167 | scopes: None, | 172 | scopes: None, |
173 | file_id, | ||
168 | } | 174 | } |
169 | } | 175 | } |
170 | } | 176 | } |
171 | 177 | ||
178 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { | ||
179 | let src = Source { file_id: self.file_id.into(), ast: expr }; | ||
180 | self.body_source_map.as_ref()?.node_expr(src) | ||
181 | } | ||
182 | |||
183 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { | ||
184 | let src = Source { file_id: self.file_id.into(), ast: pat }; | ||
185 | self.body_source_map.as_ref()?.node_pat(src) | ||
186 | } | ||
187 | |||
172 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { | 188 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { |
173 | let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; | 189 | let expr_id = self.expr_id(expr)?; |
174 | Some(self.infer.as_ref()?[expr_id].clone()) | 190 | Some(self.infer.as_ref()?[expr_id].clone()) |
175 | } | 191 | } |
176 | 192 | ||
177 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { | 193 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { |
178 | let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; | 194 | let pat_id = self.pat_id(pat)?; |
179 | Some(self.infer.as_ref()?[pat_id].clone()) | 195 | Some(self.infer.as_ref()?[pat_id].clone()) |
180 | } | 196 | } |
181 | 197 | ||
@@ -188,22 +204,22 @@ impl SourceAnalyzer { | |||
188 | } | 204 | } |
189 | 205 | ||
190 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 206 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
191 | let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?; | 207 | let expr_id = self.expr_id(&call.clone().into())?; |
192 | self.infer.as_ref()?.method_resolution(expr_id) | 208 | self.infer.as_ref()?.method_resolution(expr_id) |
193 | } | 209 | } |
194 | 210 | ||
195 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | 211 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { |
196 | let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?; | 212 | let expr_id = self.expr_id(&field.clone().into())?; |
197 | self.infer.as_ref()?.field_resolution(expr_id) | 213 | self.infer.as_ref()?.field_resolution(expr_id) |
198 | } | 214 | } |
199 | 215 | ||
200 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { | 216 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { |
201 | let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?; | 217 | let expr_id = self.expr_id(&record_lit.clone().into())?; |
202 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) | 218 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id) |
203 | } | 219 | } |
204 | 220 | ||
205 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { | 221 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { |
206 | let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?; | 222 | let pat_id = self.pat_id(&record_pat.clone().into())?; |
207 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) | 223 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id) |
208 | } | 224 | } |
209 | 225 | ||
@@ -224,7 +240,10 @@ impl SourceAnalyzer { | |||
224 | ) -> Option<PathResolution> { | 240 | ) -> Option<PathResolution> { |
225 | let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { | 241 | let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { |
226 | TypeNs::SelfType(it) => PathResolution::SelfType(it), | 242 | TypeNs::SelfType(it) => PathResolution::SelfType(it), |
227 | TypeNs::GenericParam(it) => PathResolution::GenericParam(it), | 243 | TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam { |
244 | parent: self.resolver.generic_def().unwrap(), | ||
245 | idx, | ||
246 | }), | ||
228 | TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()), | 247 | TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()), |
229 | TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), | 248 | TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), |
230 | TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), | 249 | TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), |
@@ -233,16 +252,9 @@ impl SourceAnalyzer { | |||
233 | }); | 252 | }); |
234 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { | 253 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { |
235 | let res = match val { | 254 | let res = match val { |
236 | ValueNs::LocalBinding(it) => { | 255 | ValueNs::LocalBinding(pat_id) => { |
237 | // We get a `PatId` from resolver, but it actually can only | 256 | let var = Local { parent: self.body_owner?, pat_id }; |
238 | // point at `BindPat`, and not at the arbitrary pattern. | 257 | PathResolution::Local(var) |
239 | let pat_ptr = self | ||
240 | .body_source_map | ||
241 | .as_ref()? | ||
242 | .pat_syntax(it)? | ||
243 | .ast // FIXME: ignoring file_id here is definitelly wrong | ||
244 | .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); | ||
245 | PathResolution::LocalBinding(pat_ptr) | ||
246 | } | 258 | } |
247 | ValueNs::Function(it) => PathResolution::Def(it.into()), | 259 | ValueNs::Function(it) => PathResolution::Def(it.into()), |
248 | ValueNs::Const(it) => PathResolution::Def(it.into()), | 260 | ValueNs::Const(it) => PathResolution::Def(it.into()), |
@@ -265,13 +277,13 @@ impl SourceAnalyzer { | |||
265 | 277 | ||
266 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | 278 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { |
267 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | 279 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { |
268 | let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?; | 280 | let expr_id = self.expr_id(&path_expr.into())?; |
269 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 281 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { |
270 | return Some(PathResolution::AssocItem(assoc)); | 282 | return Some(PathResolution::AssocItem(assoc)); |
271 | } | 283 | } |
272 | } | 284 | } |
273 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | 285 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { |
274 | let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?; | 286 | let pat_id = self.pat_id(&path_pat.into())?; |
275 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { | 287 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { |
276 | return Some(PathResolution::AssocItem(assoc)); | 288 | return Some(PathResolution::AssocItem(assoc)); |
277 | } | 289 | } |
@@ -286,7 +298,7 @@ impl SourceAnalyzer { | |||
286 | let name = name_ref.as_name(); | 298 | let name = name_ref.as_name(); |
287 | let source_map = self.body_source_map.as_ref()?; | 299 | let source_map = self.body_source_map.as_ref()?; |
288 | let scopes = self.scopes.as_ref()?; | 300 | let scopes = self.scopes.as_ref()?; |
289 | let scope = scope_for(scopes, source_map, name_ref.syntax()); | 301 | let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); |
290 | let ret = scopes | 302 | let ret = scopes |
291 | .scope_chain(scope) | 303 | .scope_chain(scope) |
292 | .flat_map(|scope| scopes.entries(scope).iter()) | 304 | .flat_map(|scope| scopes.entries(scope).iter()) |
@@ -419,11 +431,12 @@ impl SourceAnalyzer { | |||
419 | fn scope_for( | 431 | fn scope_for( |
420 | scopes: &ExprScopes, | 432 | scopes: &ExprScopes, |
421 | source_map: &BodySourceMap, | 433 | source_map: &BodySourceMap, |
434 | file_id: HirFileId, | ||
422 | node: &SyntaxNode, | 435 | node: &SyntaxNode, |
423 | ) -> Option<ScopeId> { | 436 | ) -> Option<ScopeId> { |
424 | node.ancestors() | 437 | node.ancestors() |
425 | .filter_map(ast::Expr::cast) | 438 | .filter_map(ast::Expr::cast) |
426 | .filter_map(|it| source_map.node_expr(&it)) | 439 | .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) |
427 | .find_map(|it| scopes.scope_for(it)) | 440 | .find_map(|it| scopes.scope_for(it)) |
428 | } | 441 | } |
429 | 442 | ||