diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-13 12:17:48 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-04-13 12:17:48 +0100 |
commit | 8887782c4ab97d22f3d5c10e142407e4371c5c61 (patch) | |
tree | 80b60b2c0c2f6104b98e16648b95d99d9b1d3463 /crates/ra_hir/src | |
parent | 34a05b7fea4add78446b2d93a64538982abacb9f (diff) | |
parent | 2facb5e061971afbf6bd2fabe3966d5de9d46489 (diff) |
Merge #1129
1129: introduce SourceAnalyzer API for ides r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 30 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 232 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 406 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 62 |
10 files changed, 408 insertions, 414 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index f13a6b37a..5d8cf57b6 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -4,7 +4,7 @@ use ra_db::{CrateId, SourceRootId, Edition}; | |||
4 | use ra_syntax::{ast::self, TreeArc}; | 4 | use ra_syntax::{ast::self, TreeArc}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | Name, ScopesWithSourceMap, Ty, HirFileId, Either, | 7 | Name, Ty, HirFileId, Either, |
8 | HirDatabase, DefDatabase, | 8 | HirDatabase, DefDatabase, |
9 | type_ref::TypeRef, | 9 | type_ref::TypeRef, |
10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, | 10 | nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, |
@@ -189,7 +189,7 @@ impl Module { | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
192 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 192 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
193 | let def_map = db.crate_def_map(self.krate); | 193 | let def_map = db.crate_def_map(self.krate); |
194 | Resolver::default().push_module_scope(def_map, self.module_id) | 194 | Resolver::default().push_module_scope(def_map, self.module_id) |
195 | } | 195 | } |
@@ -313,7 +313,7 @@ impl Struct { | |||
313 | 313 | ||
314 | // FIXME move to a more general type | 314 | // FIXME move to a more general type |
315 | /// Builds a resolver for type references inside this struct. | 315 | /// Builds a resolver for type references inside this struct. |
316 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 316 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
317 | // take the outer scope... | 317 | // take the outer scope... |
318 | let r = self.module(db).resolver(db); | 318 | let r = self.module(db).resolver(db); |
319 | // ...and add generic params, if present | 319 | // ...and add generic params, if present |
@@ -373,7 +373,7 @@ impl Enum { | |||
373 | 373 | ||
374 | // FIXME: move to a more general type | 374 | // FIXME: move to a more general type |
375 | /// Builds a resolver for type references inside this struct. | 375 | /// Builds a resolver for type references inside this struct. |
376 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 376 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
377 | // take the outer scope... | 377 | // take the outer scope... |
378 | let r = self.module(db).resolver(db); | 378 | let r = self.module(db).resolver(db); |
379 | // ...and add generic params, if present | 379 | // ...and add generic params, if present |
@@ -450,28 +450,22 @@ impl DefWithBody { | |||
450 | db.infer(*self) | 450 | db.infer(*self) |
451 | } | 451 | } |
452 | 452 | ||
453 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
454 | db.body_with_source_map(*self).1 | ||
455 | } | ||
456 | |||
457 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | 453 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { |
458 | db.body_hir(*self) | 454 | db.body_hir(*self) |
459 | } | 455 | } |
460 | 456 | ||
457 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
458 | db.body_with_source_map(*self).1 | ||
459 | } | ||
460 | |||
461 | /// Builds a resolver for code inside this item. | 461 | /// Builds a resolver for code inside this item. |
462 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 462 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
463 | match *self { | 463 | match *self { |
464 | DefWithBody::Const(ref c) => c.resolver(db), | 464 | DefWithBody::Const(ref c) => c.resolver(db), |
465 | DefWithBody::Function(ref f) => f.resolver(db), | 465 | DefWithBody::Function(ref f) => f.resolver(db), |
466 | DefWithBody::Static(ref s) => s.resolver(db), | 466 | DefWithBody::Static(ref s) => s.resolver(db), |
467 | } | 467 | } |
468 | } | 468 | } |
469 | |||
470 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | ||
471 | let scopes = db.expr_scopes(*self); | ||
472 | let source_map = db.body_with_source_map(*self).1; | ||
473 | ScopesWithSourceMap { scopes, source_map } | ||
474 | } | ||
475 | } | 469 | } |
476 | 470 | ||
477 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 471 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -523,7 +517,7 @@ impl Function { | |||
523 | self.signature(db).name.clone() | 517 | self.signature(db).name.clone() |
524 | } | 518 | } |
525 | 519 | ||
526 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 520 | pub(crate) fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
527 | db.body_with_source_map((*self).into()).1 | 521 | db.body_with_source_map((*self).into()).1 |
528 | } | 522 | } |
529 | 523 | ||
@@ -535,12 +529,6 @@ impl Function { | |||
535 | db.type_for_def((*self).into(), Namespace::Values) | 529 | db.type_for_def((*self).into(), Namespace::Values) |
536 | } | 530 | } |
537 | 531 | ||
538 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | ||
539 | let scopes = db.expr_scopes((*self).into()); | ||
540 | let source_map = db.body_with_source_map((*self).into()).1; | ||
541 | ScopesWithSourceMap { scopes, source_map } | ||
542 | } | ||
543 | |||
544 | pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> { | 532 | pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> { |
545 | db.fn_signature(*self) | 533 | db.fn_signature(*self) |
546 | } | 534 | } |
@@ -561,7 +549,7 @@ impl Function { | |||
561 | 549 | ||
562 | // FIXME: move to a more general type for 'body-having' items | 550 | // FIXME: move to a more general type for 'body-having' items |
563 | /// Builds a resolver for code inside this item. | 551 | /// Builds a resolver for code inside this item. |
564 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 552 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
565 | // take the outer scope... | 553 | // take the outer scope... |
566 | let r = self | 554 | let r = self |
567 | .impl_block(db) | 555 | .impl_block(db) |
@@ -606,10 +594,6 @@ impl Const { | |||
606 | db.infer((*self).into()) | 594 | db.infer((*self).into()) |
607 | } | 595 | } |
608 | 596 | ||
609 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
610 | db.body_with_source_map((*self).into()).1 | ||
611 | } | ||
612 | |||
613 | /// The containing impl block, if this is a method. | 597 | /// The containing impl block, if this is a method. |
614 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { | 598 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { |
615 | let module_impls = db.impls_in_module(self.module(db)); | 599 | let module_impls = db.impls_in_module(self.module(db)); |
@@ -618,7 +602,7 @@ impl Const { | |||
618 | 602 | ||
619 | // FIXME: move to a more general type for 'body-having' items | 603 | // FIXME: move to a more general type for 'body-having' items |
620 | /// Builds a resolver for code inside this item. | 604 | /// Builds a resolver for code inside this item. |
621 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 605 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
622 | // take the outer scope... | 606 | // take the outer scope... |
623 | let r = self | 607 | let r = self |
624 | .impl_block(db) | 608 | .impl_block(db) |
@@ -670,7 +654,7 @@ impl Static { | |||
670 | } | 654 | } |
671 | 655 | ||
672 | /// Builds a resolver for code inside this item. | 656 | /// Builds a resolver for code inside this item. |
673 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 657 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
674 | // take the outer scope... | 658 | // take the outer scope... |
675 | self.module(db).resolver(db) | 659 | self.module(db).resolver(db) |
676 | } | 660 | } |
@@ -678,10 +662,6 @@ impl Static { | |||
678 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 662 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
679 | db.infer((*self).into()) | 663 | db.infer((*self).into()) |
680 | } | 664 | } |
681 | |||
682 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
683 | db.body_with_source_map((*self).into()).1 | ||
684 | } | ||
685 | } | 665 | } |
686 | 666 | ||
687 | impl Docs for Static { | 667 | impl Docs for Static { |
@@ -756,7 +736,7 @@ impl TypeAlias { | |||
756 | } | 736 | } |
757 | 737 | ||
758 | /// Builds a resolver for the type references in this type alias. | 738 | /// Builds a resolver for the type references in this type alias. |
759 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 739 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
760 | // take the outer scope... | 740 | // take the outer scope... |
761 | let r = self | 741 | let r = self |
762 | .impl_block(db) | 742 | .impl_block(db) |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index a8e115e47..817e660f9 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -14,9 +14,9 @@ use crate::{ | |||
14 | name::AsName, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
17 | use crate::{ path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; | 17 | use crate::{path::GenericArgs, ty::primitive::{IntTy, UncertainIntTy, FloatTy, UncertainFloatTy}}; |
18 | 18 | ||
19 | pub use self::scope::{ExprScopes, ScopesWithSourceMap, ScopeEntryWithSyntax}; | 19 | pub use self::scope::ExprScopes; |
20 | 20 | ||
21 | pub(crate) mod scope; | 21 | pub(crate) mod scope; |
22 | 22 | ||
@@ -81,19 +81,23 @@ impl Body { | |||
81 | } | 81 | } |
82 | 82 | ||
83 | // needs arbitrary_self_types to be a method... or maybe move to the def? | 83 | // needs arbitrary_self_types to be a method... or maybe move to the def? |
84 | pub fn resolver_for_expr(body: Arc<Body>, db: &impl HirDatabase, expr_id: ExprId) -> Resolver { | 84 | pub(crate) fn resolver_for_expr( |
85 | body: Arc<Body>, | ||
86 | db: &impl HirDatabase, | ||
87 | expr_id: ExprId, | ||
88 | ) -> Resolver { | ||
85 | let scopes = db.expr_scopes(body.owner); | 89 | let scopes = db.expr_scopes(body.owner); |
86 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) | 90 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) |
87 | } | 91 | } |
88 | 92 | ||
89 | pub fn resolver_for_scope( | 93 | pub(crate) fn resolver_for_scope( |
90 | body: Arc<Body>, | 94 | body: Arc<Body>, |
91 | db: &impl HirDatabase, | 95 | db: &impl HirDatabase, |
92 | scope_id: Option<scope::ScopeId>, | 96 | scope_id: Option<scope::ScopeId>, |
93 | ) -> Resolver { | 97 | ) -> Resolver { |
94 | let mut r = body.owner.resolver(db); | 98 | let mut r = body.owner.resolver(db); |
95 | let scopes = db.expr_scopes(body.owner); | 99 | let scopes = db.expr_scopes(body.owner); |
96 | let scope_chain = scopes.scope_chain_for(scope_id).collect::<Vec<_>>(); | 100 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); |
97 | for scope in scope_chain.into_iter().rev() { | 101 | for scope in scope_chain.into_iter().rev() { |
98 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | 102 | r = r.push_expr_scope(Arc::clone(&scopes), scope); |
99 | } | 103 | } |
@@ -117,31 +121,27 @@ impl Index<PatId> for Body { | |||
117 | } | 121 | } |
118 | 122 | ||
119 | impl BodySourceMap { | 123 | impl BodySourceMap { |
120 | pub fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> { | 124 | pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<SyntaxNodePtr> { |
121 | self.expr_map_back.get(expr).cloned() | 125 | self.expr_map_back.get(expr).cloned() |
122 | } | 126 | } |
123 | 127 | ||
124 | pub fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> { | 128 | pub(crate) fn syntax_expr(&self, ptr: SyntaxNodePtr) -> Option<ExprId> { |
125 | self.expr_map.get(&ptr).cloned() | 129 | self.expr_map.get(&ptr).cloned() |
126 | } | 130 | } |
127 | 131 | ||
128 | pub fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { | 132 | pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { |
129 | self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() | 133 | self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() |
130 | } | 134 | } |
131 | 135 | ||
132 | pub fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { | 136 | pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { |
133 | self.pat_map_back.get(pat).cloned() | 137 | self.pat_map_back.get(pat).cloned() |
134 | } | 138 | } |
135 | 139 | ||
136 | pub fn syntax_pat(&self, ptr: PatPtr) -> Option<PatId> { | 140 | pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { |
137 | self.pat_map.get(&ptr).cloned() | ||
138 | } | ||
139 | |||
140 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | ||
141 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() | 141 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() |
142 | } | 142 | } |
143 | 143 | ||
144 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { | 144 | pub(crate) fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { |
145 | self.field_map[&(expr, field)].clone() | 145 | self.field_map[&(expr, field)].clone() |
146 | } | 146 | } |
147 | } | 147 | } |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 725b6c00e..58f365128 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -1,17 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::FxHashMap; |
4 | |||
5 | use ra_syntax::{ | ||
6 | AstNode, SyntaxNode, TextUnit, TextRange, SyntaxNodePtr, AstPtr, | ||
7 | algo::generate, | ||
8 | ast, | ||
9 | }; | ||
10 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id}; |
11 | 5 | ||
12 | use crate::{ | 6 | use crate::{ |
13 | Name, AsName,DefWithBody, Either, | 7 | Name, DefWithBody, |
14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, | 8 | expr::{PatId, ExprId, Pat, Expr, Body, Statement}, |
15 | HirDatabase, | 9 | HirDatabase, |
16 | }; | 10 | }; |
17 | 11 | ||
@@ -23,23 +17,32 @@ impl_arena_id!(ScopeId); | |||
23 | pub struct ExprScopes { | 17 | pub struct ExprScopes { |
24 | body: Arc<Body>, | 18 | body: Arc<Body>, |
25 | scopes: Arena<ScopeId, ScopeData>, | 19 | scopes: Arena<ScopeId, ScopeData>, |
26 | scope_for: FxHashMap<ExprId, ScopeId>, | 20 | scope_by_expr: FxHashMap<ExprId, ScopeId>, |
27 | } | 21 | } |
28 | 22 | ||
29 | #[derive(Debug, PartialEq, Eq)] | 23 | #[derive(Debug, PartialEq, Eq)] |
30 | pub struct ScopeEntry { | 24 | pub(crate) struct ScopeEntry { |
31 | name: Name, | 25 | name: Name, |
32 | pat: PatId, | 26 | pat: PatId, |
33 | } | 27 | } |
34 | 28 | ||
29 | impl ScopeEntry { | ||
30 | pub(crate) fn name(&self) -> &Name { | ||
31 | &self.name | ||
32 | } | ||
33 | |||
34 | pub(crate) fn pat(&self) -> PatId { | ||
35 | self.pat | ||
36 | } | ||
37 | } | ||
38 | |||
35 | #[derive(Debug, PartialEq, Eq)] | 39 | #[derive(Debug, PartialEq, Eq)] |
36 | pub struct ScopeData { | 40 | pub(crate) struct ScopeData { |
37 | parent: Option<ScopeId>, | 41 | parent: Option<ScopeId>, |
38 | entries: Vec<ScopeEntry>, | 42 | entries: Vec<ScopeEntry>, |
39 | } | 43 | } |
40 | 44 | ||
41 | impl ExprScopes { | 45 | impl ExprScopes { |
42 | // FIXME: This should take something more general than Function | ||
43 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { | 46 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { |
44 | let body = db.body_hir(def); | 47 | let body = db.body_hir(def); |
45 | let res = ExprScopes::new(body); | 48 | let res = ExprScopes::new(body); |
@@ -50,7 +53,7 @@ impl ExprScopes { | |||
50 | let mut scopes = ExprScopes { | 53 | let mut scopes = ExprScopes { |
51 | body: body.clone(), | 54 | body: body.clone(), |
52 | scopes: Arena::default(), | 55 | scopes: Arena::default(), |
53 | scope_for: FxHashMap::default(), | 56 | scope_by_expr: FxHashMap::default(), |
54 | }; | 57 | }; |
55 | let root = scopes.root_scope(); | 58 | let root = scopes.root_scope(); |
56 | scopes.add_params_bindings(root, body.params()); | 59 | scopes.add_params_bindings(root, body.params()); |
@@ -58,19 +61,23 @@ impl ExprScopes { | |||
58 | scopes | 61 | scopes |
59 | } | 62 | } |
60 | 63 | ||
61 | pub fn body(&self) -> Arc<Body> { | 64 | pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
62 | self.body.clone() | ||
63 | } | ||
64 | |||
65 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | ||
66 | &self.scopes[scope].entries | 65 | &self.scopes[scope].entries |
67 | } | 66 | } |
68 | 67 | ||
69 | pub fn scope_chain_for<'a>( | 68 | pub(crate) fn scope_chain<'a>( |
70 | &'a self, | 69 | &'a self, |
71 | scope: Option<ScopeId>, | 70 | scope: Option<ScopeId>, |
72 | ) -> impl Iterator<Item = ScopeId> + 'a { | 71 | ) -> impl Iterator<Item = ScopeId> + 'a { |
73 | generate(scope, move |&scope| self.scopes[scope].parent) | 72 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) |
73 | } | ||
74 | |||
75 | pub(crate) fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
76 | self.scope_by_expr.get(&expr).map(|&scope| scope) | ||
77 | } | ||
78 | |||
79 | pub(crate) fn scope_by_expr(&self) -> &FxHashMap<ExprId, ScopeId> { | ||
80 | &self.scope_by_expr | ||
74 | } | 81 | } |
75 | 82 | ||
76 | fn root_scope(&mut self) -> ScopeId { | 83 | fn root_scope(&mut self) -> ScopeId { |
@@ -99,130 +106,7 @@ impl ExprScopes { | |||
99 | } | 106 | } |
100 | 107 | ||
101 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | 108 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { |
102 | self.scope_for.insert(node, scope); | 109 | self.scope_by_expr.insert(node, scope); |
103 | } | ||
104 | |||
105 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
106 | self.scope_for.get(&expr).map(|&scope| scope) | ||
107 | } | ||
108 | } | ||
109 | |||
110 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
111 | pub struct ScopesWithSourceMap { | ||
112 | pub source_map: Arc<BodySourceMap>, | ||
113 | pub scopes: Arc<ExprScopes>, | ||
114 | } | ||
115 | |||
116 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
117 | pub struct ScopeEntryWithSyntax { | ||
118 | name: Name, | ||
119 | ptr: Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>, | ||
120 | } | ||
121 | |||
122 | impl ScopeEntryWithSyntax { | ||
123 | pub fn name(&self) -> &Name { | ||
124 | &self.name | ||
125 | } | ||
126 | |||
127 | pub fn ptr(&self) -> Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>> { | ||
128 | self.ptr | ||
129 | } | ||
130 | } | ||
131 | |||
132 | impl ScopesWithSourceMap { | ||
133 | fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a { | ||
134 | generate(self.scope_for(node), move |&scope| self.scopes.scopes[scope].parent) | ||
135 | } | ||
136 | |||
137 | pub fn scope_for_offset(&self, offset: TextUnit) -> Option<ScopeId> { | ||
138 | self.scopes | ||
139 | .scope_for | ||
140 | .iter() | ||
141 | .filter_map(|(id, scope)| Some((self.source_map.expr_syntax(*id)?, scope))) | ||
142 | // find containing scope | ||
143 | .min_by_key(|(ptr, _scope)| { | ||
144 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) | ||
145 | }) | ||
146 | .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)) | ||
147 | } | ||
148 | |||
149 | // XXX: during completion, cursor might be outside of any particular | ||
150 | // expression. Try to figure out the correct scope... | ||
151 | // FIXME: move this to source binder? | ||
152 | fn adjust(&self, ptr: SyntaxNodePtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { | ||
153 | let r = ptr.range(); | ||
154 | let child_scopes = self | ||
155 | .scopes | ||
156 | .scope_for | ||
157 | .iter() | ||
158 | .filter_map(|(id, scope)| Some((self.source_map.expr_syntax(*id)?, scope))) | ||
159 | .map(|(ptr, scope)| (ptr.range(), scope)) | ||
160 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | ||
161 | |||
162 | child_scopes | ||
163 | .max_by(|(r1, _), (r2, _)| { | ||
164 | if r2.is_subrange(&r1) { | ||
165 | std::cmp::Ordering::Greater | ||
166 | } else if r1.is_subrange(&r2) { | ||
167 | std::cmp::Ordering::Less | ||
168 | } else { | ||
169 | r1.start().cmp(&r2.start()) | ||
170 | } | ||
171 | }) | ||
172 | .map(|(_ptr, scope)| *scope) | ||
173 | .unwrap_or(original_scope) | ||
174 | } | ||
175 | |||
176 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | ||
177 | let mut shadowed = FxHashSet::default(); | ||
178 | let name = name_ref.as_name(); | ||
179 | let ret = self | ||
180 | .scope_chain(name_ref.syntax()) | ||
181 | .flat_map(|scope| self.scopes.entries(scope).iter()) | ||
182 | .filter(|entry| shadowed.insert(entry.name())) | ||
183 | .filter(|entry| entry.name() == &name) | ||
184 | .nth(0); | ||
185 | ret.and_then(|entry| { | ||
186 | Some(ScopeEntryWithSyntax { | ||
187 | name: entry.name().clone(), | ||
188 | ptr: self.source_map.pat_syntax(entry.pat())?, | ||
189 | }) | ||
190 | }) | ||
191 | } | ||
192 | |||
193 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | ||
194 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | ||
195 | let ptr = Either::A(AstPtr::new(pat.into())); | ||
196 | fn_def | ||
197 | .syntax() | ||
198 | .descendants() | ||
199 | .filter_map(ast::NameRef::cast) | ||
200 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | ||
201 | None => false, | ||
202 | Some(entry) => entry.ptr() == ptr, | ||
203 | }) | ||
204 | .map(|name_ref| ReferenceDescriptor { | ||
205 | name: name_ref.syntax().text().to_string(), | ||
206 | range: name_ref.syntax().range(), | ||
207 | }) | ||
208 | .collect() | ||
209 | } | ||
210 | |||
211 | pub fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> { | ||
212 | node.ancestors() | ||
213 | .map(SyntaxNodePtr::new) | ||
214 | .filter_map(|ptr| self.source_map.syntax_expr(ptr)) | ||
215 | .find_map(|it| self.scopes.scope_for(it)) | ||
216 | } | ||
217 | } | ||
218 | |||
219 | impl ScopeEntry { | ||
220 | pub fn name(&self) -> &Name { | ||
221 | &self.name | ||
222 | } | ||
223 | |||
224 | pub fn pat(&self) -> PatId { | ||
225 | self.pat | ||
226 | } | 110 | } |
227 | } | 111 | } |
228 | 112 | ||
@@ -286,22 +170,13 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
286 | }; | 170 | }; |
287 | } | 171 | } |
288 | 172 | ||
289 | #[derive(Debug)] | ||
290 | pub struct ReferenceDescriptor { | ||
291 | pub range: TextRange, | ||
292 | pub name: String, | ||
293 | } | ||
294 | |||
295 | #[cfg(test)] | 173 | #[cfg(test)] |
296 | mod tests { | 174 | mod tests { |
297 | use ra_db::salsa::InternKey; | 175 | use ra_db::SourceDatabase; |
298 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; | 176 | use ra_syntax::{algo::find_node_at_offset, AstNode, SyntaxNodePtr, ast}; |
299 | use test_utils::{extract_offset, assert_eq_text}; | 177 | use test_utils::{extract_offset, assert_eq_text}; |
300 | use crate::Function; | ||
301 | |||
302 | use crate::expr::{ExprCollector}; | ||
303 | 178 | ||
304 | use super::*; | 179 | use crate::{source_binder::SourceAnalyzer, mock::MockDatabase}; |
305 | 180 | ||
306 | fn do_check(code: &str, expected: &[&str]) { | 181 | fn do_check(code: &str, expected: &[&str]) { |
307 | let (off, code) = extract_offset(code); | 182 | let (off, code) = extract_offset(code); |
@@ -313,18 +188,20 @@ mod tests { | |||
313 | buf.push_str(&code[off..]); | 188 | buf.push_str(&code[off..]); |
314 | buf | 189 | buf |
315 | }; | 190 | }; |
316 | let file = SourceFile::parse(&code); | 191 | |
192 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | ||
193 | let file = db.parse(file_id); | ||
317 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 194 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
318 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 195 | let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); |
319 | let irrelevant_function = | 196 | |
320 | Function { id: crate::ids::FunctionId::from_intern_id(0u32.into()) }; | 197 | let scopes = analyzer.scopes(); |
321 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); | 198 | let expr_id = |
322 | let scopes = ExprScopes::new(Arc::new(body)); | 199 | analyzer.body_source_map().syntax_expr(SyntaxNodePtr::new(marker.syntax())).unwrap(); |
323 | let scopes = | 200 | let scope = scopes.scope_for(expr_id); |
324 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 201 | |
325 | let actual = scopes | 202 | let actual = scopes |
326 | .scope_chain(marker.syntax()) | 203 | .scope_chain(scope) |
327 | .flat_map(|scope| scopes.scopes.entries(scope)) | 204 | .flat_map(|scope| scopes.entries(scope)) |
328 | .map(|it| it.name().to_string()) | 205 | .map(|it| it.name().to_string()) |
329 | .collect::<Vec<_>>() | 206 | .collect::<Vec<_>>() |
330 | .join("\n"); | 207 | .join("\n"); |
@@ -407,28 +284,17 @@ mod tests { | |||
407 | ); | 284 | ); |
408 | } | 285 | } |
409 | 286 | ||
410 | fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) { | ||
411 | let mut collector = ExprCollector::new(DefWithBody::Function(function)); | ||
412 | collector.collect_fn_body(node); | ||
413 | collector.finish() | ||
414 | } | ||
415 | |||
416 | fn do_check_local_name(code: &str, expected_offset: u32) { | 287 | fn do_check_local_name(code: &str, expected_offset: u32) { |
417 | let (off, code) = extract_offset(code); | 288 | let (off, code) = extract_offset(code); |
418 | let file = SourceFile::parse(&code); | 289 | |
290 | let (db, _source_root, file_id) = MockDatabase::with_single_file(&code); | ||
291 | let file = db.parse(file_id); | ||
419 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) | 292 | let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) |
420 | .expect("failed to find a name at the target offset"); | 293 | .expect("failed to find a name at the target offset"); |
421 | |||
422 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
423 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 294 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
295 | let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); | ||
424 | 296 | ||
425 | let irrelevant_function = | 297 | let local_name_entry = analyzer.resolve_local_name(name_ref).unwrap(); |
426 | Function { id: crate::ids::FunctionId::from_intern_id(0u32.into()) }; | ||
427 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); | ||
428 | let scopes = ExprScopes::new(Arc::new(body)); | ||
429 | let scopes = | ||
430 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | ||
431 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); | ||
432 | let local_name = | 298 | let local_name = |
433 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | 299 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); |
434 | assert_eq!(local_name.range(), expected_name.syntax().range()); | 300 | assert_eq!(local_name.range(), expected_name.syntax().range()); |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 40d368cd9..b306874cc 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -105,7 +105,7 @@ impl ImplBlock { | |||
105 | db.generic_params((*self).into()) | 105 | db.generic_params((*self).into()) |
106 | } | 106 | } |
107 | 107 | ||
108 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | 108 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> Resolver { |
109 | let r = self.module().resolver(db); | 109 | let r = self.module().resolver(db); |
110 | // add generic params, if present | 110 | // add generic params, if present |
111 | let p = self.generic_params(db); | 111 | let p = self.generic_params(db); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 0881939a2..a9db23060 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -51,6 +51,7 @@ use crate::{ | |||
51 | db::{HirDatabase, DefDatabase}, | 51 | db::{HirDatabase, DefDatabase}, |
52 | name::{AsName, KnownName}, | 52 | name::{AsName, KnownName}, |
53 | source_id::{FileAstId, AstId}, | 53 | source_id::{FileAstId, AstId}, |
54 | resolve::Resolver, | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | pub use self::{ | 57 | pub use self::{ |
@@ -60,12 +61,13 @@ pub use self::{ | |||
60 | source_id::{AstIdMap, ErasedFileAstId}, | 61 | source_id::{AstIdMap, ErasedFileAstId}, |
61 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc}, | 62 | ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc}, |
62 | nameres::{PerNs, Namespace, ImportId}, | 63 | nameres::{PerNs, Namespace, ImportId}, |
63 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, | 64 | ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay, CallableDef}, |
64 | impl_block::{ImplBlock, ImplItem}, | 65 | impl_block::{ImplBlock, ImplItem}, |
65 | docs::{Docs, Documentation}, | 66 | docs::{Docs, Documentation}, |
66 | adt::AdtDef, | 67 | adt::AdtDef, |
67 | expr::{ExprScopes, ScopesWithSourceMap, ScopeEntryWithSyntax}, | 68 | expr::ExprScopes, |
68 | resolve::{Resolver, Resolution}, | 69 | resolve::Resolution, |
70 | source_binder::{SourceAnalyzer, PathResolution, ScopeEntryWithSyntax}, | ||
69 | }; | 71 | }; |
70 | 72 | ||
71 | pub use self::code_model_api::{ | 73 | pub use self::code_model_api::{ |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2609585b1..685f4b8b1 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -9,13 +9,13 @@ use crate::{ | |||
9 | name::{Name, KnownName}, | 9 | name::{Name, KnownName}, |
10 | nameres::{PerNs, CrateDefMap, CrateModuleId}, | 10 | nameres::{PerNs, CrateDefMap, CrateModuleId}, |
11 | generics::GenericParams, | 11 | generics::GenericParams, |
12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, | 12 | expr::{scope::{ExprScopes, ScopeId}, PatId}, |
13 | impl_block::ImplBlock, | 13 | impl_block::ImplBlock, |
14 | path::Path, Trait | 14 | path::Path, Trait |
15 | }; | 15 | }; |
16 | 16 | ||
17 | #[derive(Debug, Clone, Default)] | 17 | #[derive(Debug, Clone, Default)] |
18 | pub struct Resolver { | 18 | pub(crate) struct Resolver { |
19 | scopes: Vec<Scope>, | 19 | scopes: Vec<Scope>, |
20 | } | 20 | } |
21 | 21 | ||
@@ -117,7 +117,7 @@ pub enum Resolution { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | impl Resolver { | 119 | impl Resolver { |
120 | pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> { | 120 | pub(crate) fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> { |
121 | let mut resolution = PerNs::none(); | 121 | let mut resolution = PerNs::none(); |
122 | for scope in self.scopes.iter().rev() { | 122 | for scope in self.scopes.iter().rev() { |
123 | resolution = resolution.or(scope.resolve_name(db, name)); | 123 | resolution = resolution.or(scope.resolve_name(db, name)); |
@@ -154,12 +154,12 @@ impl Resolver { | |||
154 | 154 | ||
155 | /// Returns the fully resolved path if we were able to resolve it. | 155 | /// Returns the fully resolved path if we were able to resolve it. |
156 | /// otherwise returns `PerNs::none` | 156 | /// otherwise returns `PerNs::none` |
157 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { | 157 | pub(crate) fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { |
158 | // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise | 158 | // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise |
159 | self.resolve_path_segments(db, path).into_fully_resolved() | 159 | self.resolve_path_segments(db, path).into_fully_resolved() |
160 | } | 160 | } |
161 | 161 | ||
162 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { | 162 | pub(crate) fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { |
163 | let mut names = FxHashMap::default(); | 163 | let mut names = FxHashMap::default(); |
164 | for scope in self.scopes.iter().rev() { | 164 | for scope in self.scopes.iter().rev() { |
165 | scope.collect_names(db, &mut |name, res| { | 165 | scope.collect_names(db, &mut |name, res| { |
@@ -197,14 +197,6 @@ impl Resolver { | |||
197 | _ => None, | 197 | _ => None, |
198 | }) | 198 | }) |
199 | } | 199 | } |
200 | |||
201 | /// The body from which any `LocalBinding` resolutions in this resolver come. | ||
202 | pub fn body(&self) -> Option<Arc<Body>> { | ||
203 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
204 | Scope::ExprScope(expr_scope) => Some(expr_scope.expr_scopes.body()), | ||
205 | _ => None, | ||
206 | }) | ||
207 | } | ||
208 | } | 200 | } |
209 | 201 | ||
210 | impl Resolver { | 202 | impl Resolver { |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 182ed4c91..bd035ced9 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -5,16 +5,21 @@ | |||
5 | /// | 5 | /// |
6 | /// So, this modules should not be used during hir construction, it exists | 6 | /// So, this modules should not be used during hir construction, it exists |
7 | /// purely for "IDE needs". | 7 | /// purely for "IDE needs". |
8 | use std::sync::Arc; | ||
9 | |||
10 | use rustc_hash::{FxHashSet, FxHashMap}; | ||
8 | use ra_db::{FileId, FilePosition}; | 11 | use ra_db::{FileId, FilePosition}; |
9 | use ra_syntax::{ | 12 | use ra_syntax::{ |
10 | SyntaxNode, | 13 | SyntaxNode, AstPtr, TextUnit, SyntaxNodePtr, TextRange, |
11 | ast::{self, AstNode, NameOwner}, | 14 | ast::{self, AstNode, NameOwner}, |
12 | algo::{find_node_at_offset, find_token_at_offset}, | 15 | algo::find_node_at_offset, |
16 | SyntaxKind::*, | ||
13 | }; | 17 | }; |
14 | 18 | ||
15 | use crate::{ | 19 | use crate::{ |
16 | HirDatabase, Function, Struct, Enum,Const,Static, | 20 | HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name, |
17 | AsName, Module, HirFileId, Crate, Trait, Resolver, | 21 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
22 | expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, | ||
18 | ids::LocationCtx, | 23 | ids::LocationCtx, |
19 | expr, AstId | 24 | expr, AstId |
20 | }; | 25 | }; |
@@ -87,63 +92,6 @@ fn module_from_source( | |||
87 | ) | 92 | ) |
88 | } | 93 | } |
89 | 94 | ||
90 | pub fn const_from_source( | ||
91 | db: &impl HirDatabase, | ||
92 | file_id: FileId, | ||
93 | const_def: &ast::ConstDef, | ||
94 | ) -> Option<Const> { | ||
95 | let module = module_from_child_node(db, file_id, const_def.syntax())?; | ||
96 | let res = const_from_module(db, module, const_def); | ||
97 | Some(res) | ||
98 | } | ||
99 | |||
100 | pub fn const_from_module( | ||
101 | db: &impl HirDatabase, | ||
102 | module: Module, | ||
103 | const_def: &ast::ConstDef, | ||
104 | ) -> Const { | ||
105 | let (file_id, _) = module.definition_source(db); | ||
106 | let file_id = file_id.into(); | ||
107 | let ctx = LocationCtx::new(db, module, file_id); | ||
108 | Const { id: ctx.to_def(const_def) } | ||
109 | } | ||
110 | |||
111 | pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { | ||
112 | let file = db.parse(position.file_id); | ||
113 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; | ||
114 | function_from_source(db, position.file_id, fn_def) | ||
115 | } | ||
116 | |||
117 | pub fn function_from_source( | ||
118 | db: &impl HirDatabase, | ||
119 | file_id: FileId, | ||
120 | fn_def: &ast::FnDef, | ||
121 | ) -> Option<Function> { | ||
122 | let module = module_from_child_node(db, file_id, fn_def.syntax())?; | ||
123 | let res = function_from_module(db, module, fn_def); | ||
124 | Some(res) | ||
125 | } | ||
126 | |||
127 | pub fn function_from_module( | ||
128 | db: &impl HirDatabase, | ||
129 | module: Module, | ||
130 | fn_def: &ast::FnDef, | ||
131 | ) -> Function { | ||
132 | let (file_id, _) = module.definition_source(db); | ||
133 | let file_id = file_id.into(); | ||
134 | let ctx = LocationCtx::new(db, module, file_id); | ||
135 | Function { id: ctx.to_def(fn_def) } | ||
136 | } | ||
137 | |||
138 | pub fn function_from_child_node( | ||
139 | db: &impl HirDatabase, | ||
140 | file_id: FileId, | ||
141 | node: &SyntaxNode, | ||
142 | ) -> Option<Function> { | ||
143 | let fn_def = node.ancestors().find_map(ast::FnDef::cast)?; | ||
144 | function_from_source(db, file_id, fn_def) | ||
145 | } | ||
146 | |||
147 | pub fn struct_from_module( | 95 | pub fn struct_from_module( |
148 | db: &impl HirDatabase, | 96 | db: &impl HirDatabase, |
149 | module: Module, | 97 | module: Module, |
@@ -155,27 +103,6 @@ pub fn struct_from_module( | |||
155 | Struct { id: ctx.to_def(struct_def) } | 103 | Struct { id: ctx.to_def(struct_def) } |
156 | } | 104 | } |
157 | 105 | ||
158 | pub fn static_from_source( | ||
159 | db: &impl HirDatabase, | ||
160 | file_id: FileId, | ||
161 | static_def: &ast::StaticDef, | ||
162 | ) -> Option<Static> { | ||
163 | let module = module_from_child_node(db, file_id, static_def.syntax())?; | ||
164 | let res = static_from_module(db, module, static_def); | ||
165 | Some(res) | ||
166 | } | ||
167 | |||
168 | pub fn static_from_module( | ||
169 | db: &impl HirDatabase, | ||
170 | module: Module, | ||
171 | static_def: &ast::StaticDef, | ||
172 | ) -> Static { | ||
173 | let (file_id, _) = module.definition_source(db); | ||
174 | let file_id = file_id.into(); | ||
175 | let ctx = LocationCtx::new(db, module, file_id); | ||
176 | Static { id: ctx.to_def(static_def) } | ||
177 | } | ||
178 | |||
179 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { | 106 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { |
180 | let (file_id, _) = module.definition_source(db); | 107 | let (file_id, _) = module.definition_source(db); |
181 | let file_id = file_id.into(); | 108 | let file_id = file_id.into(); |
@@ -194,48 +121,6 @@ pub fn trait_from_module( | |||
194 | Trait { id: ctx.to_def(trait_def) } | 121 | Trait { id: ctx.to_def(trait_def) } |
195 | } | 122 | } |
196 | 123 | ||
197 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { | ||
198 | let file_id = position.file_id; | ||
199 | let file = db.parse(file_id); | ||
200 | find_token_at_offset(file.syntax(), position.offset) | ||
201 | .find_map(|token| { | ||
202 | token.parent().ancestors().find_map(|node| { | ||
203 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | ||
204 | if let Some(func) = function_from_child_node(db, file_id, node) { | ||
205 | let scopes = func.scopes(db); | ||
206 | let scope = scopes.scope_for_offset(position.offset); | ||
207 | Some(expr::resolver_for_scope(func.body(db), db, scope)) | ||
208 | } else { | ||
209 | // FIXME const/static/array length | ||
210 | None | ||
211 | } | ||
212 | } else { | ||
213 | try_get_resolver_for_node(db, file_id, node) | ||
214 | } | ||
215 | }) | ||
216 | }) | ||
217 | .unwrap_or_default() | ||
218 | } | ||
219 | |||
220 | pub fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> Resolver { | ||
221 | node.ancestors() | ||
222 | .find_map(|node| { | ||
223 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | ||
224 | if let Some(func) = function_from_child_node(db, file_id, node) { | ||
225 | let scopes = func.scopes(db); | ||
226 | let scope = scopes.scope_for(&node); | ||
227 | Some(expr::resolver_for_scope(func.body(db), db, scope)) | ||
228 | } else { | ||
229 | // FIXME const/static/array length | ||
230 | None | ||
231 | } | ||
232 | } else { | ||
233 | try_get_resolver_for_node(db, file_id, node) | ||
234 | } | ||
235 | }) | ||
236 | .unwrap_or_default() | ||
237 | } | ||
238 | |||
239 | fn try_get_resolver_for_node( | 124 | fn try_get_resolver_for_node( |
240 | db: &impl HirDatabase, | 125 | db: &impl HirDatabase, |
241 | file_id: FileId, | 126 | file_id: FileId, |
@@ -251,10 +136,281 @@ fn try_get_resolver_for_node( | |||
251 | } else if let Some(e) = ast::EnumDef::cast(node) { | 136 | } else if let Some(e) = ast::EnumDef::cast(node) { |
252 | let module = module_from_child_node(db, file_id, e.syntax())?; | 137 | let module = module_from_child_node(db, file_id, e.syntax())?; |
253 | Some(enum_from_module(db, module, e).resolver(db)) | 138 | Some(enum_from_module(db, module, e).resolver(db)) |
254 | } else if let Some(f) = ast::FnDef::cast(node) { | 139 | } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { |
255 | function_from_source(db, file_id, f).map(|f| f.resolver(db)) | 140 | Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) |
256 | } else { | 141 | } else { |
257 | // FIXME add missing cases | 142 | // FIXME add missing cases |
258 | None | 143 | None |
259 | } | 144 | } |
260 | } | 145 | } |
146 | |||
147 | fn def_with_body_from_child_node( | ||
148 | db: &impl HirDatabase, | ||
149 | file_id: FileId, | ||
150 | node: &SyntaxNode, | ||
151 | ) -> Option<DefWithBody> { | ||
152 | let module = module_from_child_node(db, file_id, node)?; | ||
153 | let ctx = LocationCtx::new(db, module, file_id.into()); | ||
154 | node.ancestors().find_map(|node| { | ||
155 | if let Some(def) = ast::FnDef::cast(node) { | ||
156 | return Some(Function { id: ctx.to_def(def) }.into()); | ||
157 | } | ||
158 | if let Some(def) = ast::ConstDef::cast(node) { | ||
159 | return Some(Const { id: ctx.to_def(def) }.into()); | ||
160 | } | ||
161 | if let Some(def) = ast::StaticDef::cast(node) { | ||
162 | return Some(Static { id: ctx.to_def(def) }.into()); | ||
163 | } | ||
164 | None | ||
165 | }) | ||
166 | } | ||
167 | |||
168 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | ||
169 | /// original source files. It should not be used inside the HIR itself. | ||
170 | #[derive(Debug)] | ||
171 | pub struct SourceAnalyzer { | ||
172 | resolver: Resolver, | ||
173 | body_source_map: Option<Arc<BodySourceMap>>, | ||
174 | infer: Option<Arc<crate::ty::InferenceResult>>, | ||
175 | scopes: Option<Arc<crate::expr::ExprScopes>>, | ||
176 | } | ||
177 | |||
178 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
179 | pub enum PathResolution { | ||
180 | /// An item | ||
181 | Def(crate::ModuleDef), | ||
182 | /// A local binding (only value namespace) | ||
183 | LocalBinding(Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>), | ||
184 | /// A generic parameter | ||
185 | GenericParam(u32), | ||
186 | SelfType(crate::ImplBlock), | ||
187 | AssocItem(crate::ImplItem), | ||
188 | } | ||
189 | |||
190 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
191 | pub struct ScopeEntryWithSyntax { | ||
192 | pub(crate) name: Name, | ||
193 | pub(crate) ptr: Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>, | ||
194 | } | ||
195 | |||
196 | impl ScopeEntryWithSyntax { | ||
197 | pub fn name(&self) -> &Name { | ||
198 | &self.name | ||
199 | } | ||
200 | |||
201 | pub fn ptr(&self) -> Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>> { | ||
202 | self.ptr | ||
203 | } | ||
204 | } | ||
205 | |||
206 | #[derive(Debug)] | ||
207 | pub struct ReferenceDescriptor { | ||
208 | pub range: TextRange, | ||
209 | pub name: String, | ||
210 | } | ||
211 | |||
212 | impl SourceAnalyzer { | ||
213 | pub fn new( | ||
214 | db: &impl HirDatabase, | ||
215 | file_id: FileId, | ||
216 | node: &SyntaxNode, | ||
217 | offset: Option<TextUnit>, | ||
218 | ) -> SourceAnalyzer { | ||
219 | let def_with_body = def_with_body_from_child_node(db, file_id, node); | ||
220 | if let Some(def) = def_with_body { | ||
221 | let source_map = def.body_source_map(db); | ||
222 | let scopes = db.expr_scopes(def); | ||
223 | let scope = match offset { | ||
224 | None => scope_for(&scopes, &source_map, &node), | ||
225 | Some(offset) => scope_for_offset(&scopes, &source_map, offset), | ||
226 | }; | ||
227 | let resolver = expr::resolver_for_scope(def.body(db), db, scope); | ||
228 | SourceAnalyzer { | ||
229 | resolver, | ||
230 | body_source_map: Some(source_map), | ||
231 | infer: Some(def.infer(db)), | ||
232 | scopes: Some(scopes), | ||
233 | } | ||
234 | } else { | ||
235 | SourceAnalyzer { | ||
236 | resolver: node | ||
237 | .ancestors() | ||
238 | .find_map(|node| try_get_resolver_for_node(db, file_id, node)) | ||
239 | .unwrap_or_default(), | ||
240 | body_source_map: None, | ||
241 | infer: None, | ||
242 | scopes: None, | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> { | ||
248 | let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; | ||
249 | Some(self.infer.as_ref()?[expr_id].clone()) | ||
250 | } | ||
251 | |||
252 | pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> { | ||
253 | let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; | ||
254 | Some(self.infer.as_ref()?[pat_id].clone()) | ||
255 | } | ||
256 | |||
257 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | ||
258 | let expr_id = self.body_source_map.as_ref()?.node_expr(call.into())?; | ||
259 | self.infer.as_ref()?.method_resolution(expr_id) | ||
260 | } | ||
261 | |||
262 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | ||
263 | let expr_id = self.body_source_map.as_ref()?.node_expr(field.into())?; | ||
264 | self.infer.as_ref()?.field_resolution(expr_id) | ||
265 | } | ||
266 | |||
267 | pub fn resolve_hir_path( | ||
268 | &self, | ||
269 | db: &impl HirDatabase, | ||
270 | path: &crate::Path, | ||
271 | ) -> PerNs<crate::Resolution> { | ||
272 | self.resolver.resolve_path(db, path) | ||
273 | } | ||
274 | |||
275 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | ||
276 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | ||
277 | let expr_id = self.body_source_map.as_ref()?.node_expr(path_expr.into())?; | ||
278 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | ||
279 | return Some(PathResolution::AssocItem(assoc)); | ||
280 | } | ||
281 | } | ||
282 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | ||
283 | let pat_id = self.body_source_map.as_ref()?.node_pat(path_pat.into())?; | ||
284 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { | ||
285 | return Some(PathResolution::AssocItem(assoc)); | ||
286 | } | ||
287 | } | ||
288 | let hir_path = crate::Path::from_ast(path)?; | ||
289 | let res = self.resolver.resolve_path(db, &hir_path); | ||
290 | let res = res.clone().take_types().or_else(|| res.take_values())?; | ||
291 | let res = match res { | ||
292 | crate::Resolution::Def(it) => PathResolution::Def(it), | ||
293 | crate::Resolution::LocalBinding(it) => { | ||
294 | PathResolution::LocalBinding(self.body_source_map.as_ref()?.pat_syntax(it)?) | ||
295 | } | ||
296 | crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it), | ||
297 | crate::Resolution::SelfType(it) => PathResolution::SelfType(it), | ||
298 | }; | ||
299 | Some(res) | ||
300 | } | ||
301 | |||
302 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | ||
303 | let mut shadowed = FxHashSet::default(); | ||
304 | let name = name_ref.as_name(); | ||
305 | let source_map = self.body_source_map.as_ref()?; | ||
306 | let scopes = self.scopes.as_ref()?; | ||
307 | let scope = scope_for(scopes, source_map, name_ref.syntax()); | ||
308 | let ret = scopes | ||
309 | .scope_chain(scope) | ||
310 | .flat_map(|scope| scopes.entries(scope).iter()) | ||
311 | .filter(|entry| shadowed.insert(entry.name())) | ||
312 | .filter(|entry| entry.name() == &name) | ||
313 | .nth(0); | ||
314 | ret.and_then(|entry| { | ||
315 | Some(ScopeEntryWithSyntax { | ||
316 | name: entry.name().clone(), | ||
317 | ptr: source_map.pat_syntax(entry.pat())?, | ||
318 | }) | ||
319 | }) | ||
320 | } | ||
321 | |||
322 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<crate::Resolution>> { | ||
323 | self.resolver.all_names(db) | ||
324 | } | ||
325 | |||
326 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | ||
327 | // FIXME: at least, this should work with any DefWithBody, but ideally | ||
328 | // this should be hir-based altogether | ||
329 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | ||
330 | let ptr = Either::A(AstPtr::new(pat.into())); | ||
331 | fn_def | ||
332 | .syntax() | ||
333 | .descendants() | ||
334 | .filter_map(ast::NameRef::cast) | ||
335 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | ||
336 | None => false, | ||
337 | Some(entry) => entry.ptr() == ptr, | ||
338 | }) | ||
339 | .map(|name_ref| ReferenceDescriptor { | ||
340 | name: name_ref.text().to_string(), | ||
341 | range: name_ref.syntax().range(), | ||
342 | }) | ||
343 | .collect() | ||
344 | } | ||
345 | |||
346 | #[cfg(test)] | ||
347 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { | ||
348 | self.body_source_map.clone().unwrap() | ||
349 | } | ||
350 | |||
351 | #[cfg(test)] | ||
352 | pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> { | ||
353 | self.infer.clone().unwrap() | ||
354 | } | ||
355 | |||
356 | #[cfg(test)] | ||
357 | pub(crate) fn scopes(&self) -> Arc<ExprScopes> { | ||
358 | self.scopes.clone().unwrap() | ||
359 | } | ||
360 | } | ||
361 | |||
362 | fn scope_for( | ||
363 | scopes: &ExprScopes, | ||
364 | source_map: &BodySourceMap, | ||
365 | node: &SyntaxNode, | ||
366 | ) -> Option<ScopeId> { | ||
367 | node.ancestors() | ||
368 | .map(SyntaxNodePtr::new) | ||
369 | .filter_map(|ptr| source_map.syntax_expr(ptr)) | ||
370 | .find_map(|it| scopes.scope_for(it)) | ||
371 | } | ||
372 | |||
373 | fn scope_for_offset( | ||
374 | scopes: &ExprScopes, | ||
375 | source_map: &BodySourceMap, | ||
376 | offset: TextUnit, | ||
377 | ) -> Option<ScopeId> { | ||
378 | scopes | ||
379 | .scope_by_expr() | ||
380 | .iter() | ||
381 | .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) | ||
382 | // find containing scope | ||
383 | .min_by_key(|(ptr, _scope)| { | ||
384 | (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) | ||
385 | }) | ||
386 | .map(|(ptr, scope)| adjust(scopes, source_map, ptr, offset).unwrap_or(*scope)) | ||
387 | } | ||
388 | |||
389 | // XXX: during completion, cursor might be outside of any particular | ||
390 | // expression. Try to figure out the correct scope... | ||
391 | fn adjust( | ||
392 | scopes: &ExprScopes, | ||
393 | source_map: &BodySourceMap, | ||
394 | ptr: SyntaxNodePtr, | ||
395 | offset: TextUnit, | ||
396 | ) -> Option<ScopeId> { | ||
397 | let r = ptr.range(); | ||
398 | let child_scopes = scopes | ||
399 | .scope_by_expr() | ||
400 | .iter() | ||
401 | .filter_map(|(id, scope)| Some((source_map.expr_syntax(*id)?, scope))) | ||
402 | .map(|(ptr, scope)| (ptr.range(), scope)) | ||
403 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | ||
404 | |||
405 | child_scopes | ||
406 | .max_by(|(r1, _), (r2, _)| { | ||
407 | if r2.is_subrange(&r1) { | ||
408 | std::cmp::Ordering::Greater | ||
409 | } else if r1.is_subrange(&r2) { | ||
410 | std::cmp::Ordering::Less | ||
411 | } else { | ||
412 | r1.start().cmp(&r2.start()) | ||
413 | } | ||
414 | }) | ||
415 | .map(|(_ptr, scope)| *scope) | ||
416 | } | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 20e55d92d..ecf13fbc3 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -15,10 +15,11 @@ use std::sync::Arc; | |||
15 | use std::{fmt, mem}; | 15 | use std::{fmt, mem}; |
16 | 16 | ||
17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; | 17 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait}; |
18 | use display::{HirDisplay, HirFormatter}; | ||
18 | 19 | ||
19 | pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; | 20 | pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig}; |
20 | pub(crate) use infer::{infer, InferenceResult, InferTy}; | 21 | pub(crate) use infer::{infer, InferenceResult, InferTy}; |
21 | use display::{HirDisplay, HirFormatter}; | 22 | pub use lower::CallableDef; |
22 | 23 | ||
23 | /// A type constructor or type name: this might be something like the primitive | 24 | /// A type constructor or type name: this might be something like the primitive |
24 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 25 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -288,6 +289,15 @@ impl Ty { | |||
288 | } | 289 | } |
289 | } | 290 | } |
290 | 291 | ||
292 | pub fn as_callable(&self) -> Option<(CallableDef, &Substs)> { | ||
293 | match self { | ||
294 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => { | ||
295 | Some((*callable_def, parameters)) | ||
296 | } | ||
297 | _ => None, | ||
298 | } | ||
299 | } | ||
300 | |||
291 | fn builtin_deref(&self) -> Option<Ty> { | 301 | fn builtin_deref(&self) -> Option<Ty> { |
292 | match self { | 302 | match self { |
293 | Ty::Apply(a_ty) => match a_ty.ctor { | 303 | Ty::Apply(a_ty) => match a_ty.ctor { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 3ac8dc46b..bb23246a6 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -135,7 +135,7 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { | |||
135 | impl Ty { | 135 | impl Ty { |
136 | /// Look up the method with the given name, returning the actual autoderefed | 136 | /// Look up the method with the given name, returning the actual autoderefed |
137 | /// receiver type (but without autoref applied yet). | 137 | /// receiver type (but without autoref applied yet). |
138 | pub fn lookup_method( | 138 | pub(crate) fn lookup_method( |
139 | self, | 139 | self, |
140 | db: &impl HirDatabase, | 140 | db: &impl HirDatabase, |
141 | name: &Name, | 141 | name: &Name, |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index ecc63f376..d7c2ca132 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -4,15 +4,15 @@ use std::fmt::Write; | |||
4 | use insta::assert_snapshot_matches; | 4 | use insta::assert_snapshot_matches; |
5 | 5 | ||
6 | use ra_db::{SourceDatabase, salsa::Database, FilePosition}; | 6 | use ra_db::{SourceDatabase, salsa::Database, FilePosition}; |
7 | use ra_syntax::{algo, ast::{self, AstNode}}; | 7 | use ra_syntax::{algo, ast::{self, AstNode}, SyntaxKind::*}; |
8 | use test_utils::covers; | 8 | use test_utils::covers; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | source_binder, | ||
12 | mock::MockDatabase, | 11 | mock::MockDatabase, |
13 | ty::display::HirDisplay, | 12 | ty::display::HirDisplay, |
14 | ty::InferenceResult, | 13 | ty::InferenceResult, |
15 | expr::BodySourceMap | 14 | expr::BodySourceMap, |
15 | SourceAnalyzer, | ||
16 | }; | 16 | }; |
17 | 17 | ||
18 | // These tests compare the inference results for all expressions in a file | 18 | // These tests compare the inference results for all expressions in a file |
@@ -1862,14 +1862,14 @@ fn test() { | |||
1862 | @r###" | 1862 | @r###" |
1863 | [49; 50) '0': u32 | 1863 | [49; 50) '0': u32 |
1864 | [80; 83) '101': u32 | 1864 | [80; 83) '101': u32 |
1865 | [126; 128) '99': u32 | ||
1866 | [95; 213) '{ ...NST; }': () | 1865 | [95; 213) '{ ...NST; }': () |
1867 | [138; 139) 'x': {unknown} | 1866 | [138; 139) 'x': {unknown} |
1868 | [142; 153) 'LOCAL_CONST': {unknown} | 1867 | [142; 153) 'LOCAL_CONST': {unknown} |
1869 | [163; 164) 'z': u32 | 1868 | [163; 164) 'z': u32 |
1870 | [167; 179) 'GLOBAL_CONST': u32 | 1869 | [167; 179) 'GLOBAL_CONST': u32 |
1871 | [189; 191) 'id': u32 | 1870 | [189; 191) 'id': u32 |
1872 | [194; 210) 'Foo::A..._CONST': u32"### | 1871 | [194; 210) 'Foo::A..._CONST': u32 |
1872 | [126; 128) '99': u32"### | ||
1873 | ); | 1873 | ); |
1874 | } | 1874 | } |
1875 | 1875 | ||
@@ -1891,8 +1891,6 @@ fn test() { | |||
1891 | @r###" | 1891 | @r###" |
1892 | [29; 32) '101': u32 | 1892 | [29; 32) '101': u32 |
1893 | [70; 73) '101': u32 | 1893 | [70; 73) '101': u32 |
1894 | [118; 120) '99': u32 | ||
1895 | [161; 163) '99': u32 | ||
1896 | [85; 280) '{ ...MUT; }': () | 1894 | [85; 280) '{ ...MUT; }': () |
1897 | [173; 174) 'x': {unknown} | 1895 | [173; 174) 'x': {unknown} |
1898 | [177; 189) 'LOCAL_STATIC': {unknown} | 1896 | [177; 189) 'LOCAL_STATIC': {unknown} |
@@ -1901,7 +1899,9 @@ fn test() { | |||
1901 | [229; 230) 'z': u32 | 1899 | [229; 230) 'z': u32 |
1902 | [233; 246) 'GLOBAL_STATIC': u32 | 1900 | [233; 246) 'GLOBAL_STATIC': u32 |
1903 | [256; 257) 'w': u32 | 1901 | [256; 257) 'w': u32 |
1904 | [260; 277) 'GLOBAL...IC_MUT': u32"### | 1902 | [260; 277) 'GLOBAL...IC_MUT': u32 |
1903 | [118; 120) '99': u32 | ||
1904 | [161; 163) '99': u32"### | ||
1905 | ); | 1905 | ); |
1906 | } | 1906 | } |
1907 | 1907 | ||
@@ -2302,13 +2302,10 @@ fn test() -> u64 { | |||
2302 | } | 2302 | } |
2303 | 2303 | ||
2304 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2304 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
2305 | let func = source_binder::function_from_position(db, pos).unwrap(); | 2305 | let file = db.parse(pos.file_id); |
2306 | let body_source_map = func.body_source_map(db); | 2306 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
2307 | let inference_result = func.infer(db); | 2307 | let analyzer = SourceAnalyzer::new(db, pos.file_id, expr.syntax(), Some(pos.offset)); |
2308 | let (_, syntax) = func.source(db); | 2308 | let ty = analyzer.type_of(db, expr).unwrap(); |
2309 | let node = algo::find_node_at_offset::<ast::Expr>(syntax.syntax(), pos.offset).unwrap(); | ||
2310 | let expr = body_source_map.node_expr(node).unwrap(); | ||
2311 | let ty = &inference_result[expr]; | ||
2312 | ty.display(db).to_string() | 2309 | ty.display(db).to_string() |
2313 | } | 2310 | } |
2314 | 2311 | ||
@@ -2350,25 +2347,11 @@ fn infer(content: &str) -> String { | |||
2350 | } | 2347 | } |
2351 | }; | 2348 | }; |
2352 | 2349 | ||
2353 | for const_def in source_file.syntax().descendants().filter_map(ast::ConstDef::cast) { | 2350 | for node in source_file.syntax().descendants() { |
2354 | let konst = source_binder::const_from_source(&db, file_id, const_def).unwrap(); | 2351 | if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { |
2355 | let inference_result = konst.infer(&db); | 2352 | let analyzer = SourceAnalyzer::new(&db, file_id, node, None); |
2356 | let body_source_map = konst.body_source_map(&db); | 2353 | infer_def(analyzer.inference_result(), analyzer.body_source_map()); |
2357 | infer_def(inference_result, body_source_map) | 2354 | } |
2358 | } | ||
2359 | |||
2360 | for static_def in source_file.syntax().descendants().filter_map(ast::StaticDef::cast) { | ||
2361 | let static_ = source_binder::static_from_source(&db, file_id, static_def).unwrap(); | ||
2362 | let inference_result = static_.infer(&db); | ||
2363 | let body_source_map = static_.body_source_map(&db); | ||
2364 | infer_def(inference_result, body_source_map) | ||
2365 | } | ||
2366 | |||
2367 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | ||
2368 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | ||
2369 | let inference_result = func.infer(&db); | ||
2370 | let body_source_map = func.body_source_map(&db); | ||
2371 | infer_def(inference_result, body_source_map) | ||
2372 | } | 2355 | } |
2373 | 2356 | ||
2374 | acc.truncate(acc.trim_end().len()); | 2357 | acc.truncate(acc.trim_end().len()); |
@@ -2403,10 +2386,12 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
2403 | } | 2386 | } |
2404 | ", | 2387 | ", |
2405 | ); | 2388 | ); |
2406 | let func = source_binder::function_from_position(&db, pos).unwrap(); | ||
2407 | { | 2389 | { |
2390 | let file = db.parse(pos.file_id); | ||
2391 | let node = | ||
2392 | algo::find_token_at_offset(file.syntax(), pos.offset).right_biased().unwrap().parent(); | ||
2408 | let events = db.log_executed(|| { | 2393 | let events = db.log_executed(|| { |
2409 | func.infer(&db); | 2394 | SourceAnalyzer::new(&db, pos.file_id, node, None); |
2410 | }); | 2395 | }); |
2411 | assert!(format!("{:?}", events).contains("infer")) | 2396 | assert!(format!("{:?}", events).contains("infer")) |
2412 | } | 2397 | } |
@@ -2423,8 +2408,11 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | |||
2423 | db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); | 2408 | db.query_mut(ra_db::FileTextQuery).set(pos.file_id, Arc::new(new_text)); |
2424 | 2409 | ||
2425 | { | 2410 | { |
2411 | let file = db.parse(pos.file_id); | ||
2412 | let node = | ||
2413 | algo::find_token_at_offset(file.syntax(), pos.offset).right_biased().unwrap().parent(); | ||
2426 | let events = db.log_executed(|| { | 2414 | let events = db.log_executed(|| { |
2427 | func.infer(&db); | 2415 | SourceAnalyzer::new(&db, pos.file_id, node, None); |
2428 | }); | 2416 | }); |
2429 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | 2417 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) |
2430 | } | 2418 | } |