aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/source_binder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/source_binder.rs')
-rw-r--r--crates/ra_hir/src/source_binder.rs52
1 files changed, 33 insertions, 19 deletions
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index f28e9c931..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".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use hir_def::path::known; 10use hir_def::{
11use hir_expand::name::AsName; 11 expr::{ExprId, PatId},
12 path::known,
13};
14use hir_expand::{name::AsName, Source};
12use ra_db::FileId; 15use ra_db::FileId;
13use ra_syntax::{ 16use ra_syntax::{
14 ast::{self, AstNode}, 17 ast::{self, AstNode},
@@ -20,11 +23,7 @@ use rustc_hash::FxHashSet;
20 23
21use crate::{ 24use 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},
@@ -93,6 +92,8 @@ 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)]
95pub struct SourceAnalyzer { 94pub struct SourceAnalyzer {
95 // FIXME: this doesn't handle macros at all
96 file_id: FileId,
96 resolver: Resolver, 97 resolver: Resolver,
97 body_owner: Option<DefWithBody>, 98 body_owner: Option<DefWithBody>,
98 body_source_map: Option<Arc<BodySourceMap>>, 99 body_source_map: Option<Arc<BodySourceMap>>,
@@ -145,9 +146,9 @@ impl SourceAnalyzer {
145 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);
146 if let Some(def) = def_with_body { 147 if let Some(def) = def_with_body {
147 let source_map = def.body_source_map(db); 148 let source_map = def.body_source_map(db);
148 let scopes = db.expr_scopes(def); 149 let scopes = def.expr_scopes(db);
149 let scope = match offset { 150 let scope = match offset {
150 None => scope_for(&scopes, &source_map, &node), 151 None => scope_for(&scopes, &source_map, file_id.into(), &node),
151 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),
152 }; 153 };
153 let resolver = expr::resolver_for_scope(db, def, scope); 154 let resolver = expr::resolver_for_scope(db, def, scope);
@@ -157,6 +158,7 @@ impl SourceAnalyzer {
157 body_source_map: Some(source_map), 158 body_source_map: Some(source_map),
158 infer: Some(def.infer(db)), 159 infer: Some(def.infer(db)),
159 scopes: Some(scopes), 160 scopes: Some(scopes),
161 file_id,
160 } 162 }
161 } else { 163 } else {
162 SourceAnalyzer { 164 SourceAnalyzer {
@@ -168,17 +170,28 @@ impl SourceAnalyzer {
168 body_source_map: None, 170 body_source_map: None,
169 infer: None, 171 infer: None,
170 scopes: None, 172 scopes: None,
173 file_id,
171 } 174 }
172 } 175 }
173 } 176 }
174 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
175 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> {
176 let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; 189 let expr_id = self.expr_id(expr)?;
177 Some(self.infer.as_ref()?[expr_id].clone()) 190 Some(self.infer.as_ref()?[expr_id].clone())
178 } 191 }
179 192
180 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> {
181 let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; 194 let pat_id = self.pat_id(pat)?;
182 Some(self.infer.as_ref()?[pat_id].clone()) 195 Some(self.infer.as_ref()?[pat_id].clone())
183 } 196 }
184 197
@@ -191,22 +204,22 @@ impl SourceAnalyzer {
191 } 204 }
192 205
193 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 206 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
194 let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?; 207 let expr_id = self.expr_id(&call.clone().into())?;
195 self.infer.as_ref()?.method_resolution(expr_id) 208 self.infer.as_ref()?.method_resolution(expr_id)
196 } 209 }
197 210
198 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { 211 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> {
199 let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?; 212 let expr_id = self.expr_id(&field.clone().into())?;
200 self.infer.as_ref()?.field_resolution(expr_id) 213 self.infer.as_ref()?.field_resolution(expr_id)
201 } 214 }
202 215
203 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> {
204 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())?;
205 self.infer.as_ref()?.variant_resolution_for_expr(expr_id) 218 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
206 } 219 }
207 220
208 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> {
209 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())?;
210 self.infer.as_ref()?.variant_resolution_for_pat(pat_id) 223 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
211 } 224 }
212 225
@@ -264,13 +277,13 @@ impl SourceAnalyzer {
264 277
265 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> {
266 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) {
267 let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?; 280 let expr_id = self.expr_id(&path_expr.into())?;
268 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) {
269 return Some(PathResolution::AssocItem(assoc)); 282 return Some(PathResolution::AssocItem(assoc));
270 } 283 }
271 } 284 }
272 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) {
273 let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?; 286 let pat_id = self.pat_id(&path_pat.into())?;
274 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) {
275 return Some(PathResolution::AssocItem(assoc)); 288 return Some(PathResolution::AssocItem(assoc));
276 } 289 }
@@ -285,7 +298,7 @@ impl SourceAnalyzer {
285 let name = name_ref.as_name(); 298 let name = name_ref.as_name();
286 let source_map = self.body_source_map.as_ref()?; 299 let source_map = self.body_source_map.as_ref()?;
287 let scopes = self.scopes.as_ref()?; 300 let scopes = self.scopes.as_ref()?;
288 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());
289 let ret = scopes 302 let ret = scopes
290 .scope_chain(scope) 303 .scope_chain(scope)
291 .flat_map(|scope| scopes.entries(scope).iter()) 304 .flat_map(|scope| scopes.entries(scope).iter())
@@ -418,11 +431,12 @@ impl SourceAnalyzer {
418fn scope_for( 431fn scope_for(
419 scopes: &ExprScopes, 432 scopes: &ExprScopes,
420 source_map: &BodySourceMap, 433 source_map: &BodySourceMap,
434 file_id: HirFileId,
421 node: &SyntaxNode, 435 node: &SyntaxNode,
422) -> Option<ScopeId> { 436) -> Option<ScopeId> {
423 node.ancestors() 437 node.ancestors()
424 .filter_map(ast::Expr::cast) 438 .filter_map(ast::Expr::cast)
425 .filter_map(|it| source_map.node_expr(&it)) 439 .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it }))
426 .find_map(|it| scopes.scope_for(it)) 440 .find_map(|it| scopes.scope_for(it))
427} 441}
428 442