From 9c7a2aef30cb35347af646dea5a5611af1224676 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 10:26:31 +0300 Subject: Refactor Module::from_source to properly descend from root file --- crates/ra_hir/src/code_model.rs | 2 +- crates/ra_hir/src/from_source.rs | 68 +++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 33 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 962d5a8c1..dd43271f4 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -157,7 +157,7 @@ impl Module { } /// Finds a child module with the specified name. - pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option { + pub fn child(self, db: &impl DefDatabase, name: &Name) -> Option { let def_map = db.crate_def_map(self.id.krate); let child_id = def_map[self.id.module_id].children.get(name)?; Some(self.with_module_id(*child_id)) diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 9793af858..7e5523c54 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -1,6 +1,6 @@ //! FIXME: write short doc here -use hir_def::{StructId, StructOrUnionId, UnionId}; +use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId}; use hir_expand::name::AsName; use ra_syntax::{ ast::{self, AstNode, NameOwner}, @@ -10,9 +10,9 @@ use ra_syntax::{ use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, - AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, - ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, - Union, VariantDef, + Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, + Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, + VariantDef, }; pub trait FromSource: Sized { @@ -152,44 +152,48 @@ impl Local { } impl Module { - pub fn from_declaration(db: &impl HirDatabase, src: Source) -> Option { - let src_parent = Source { - file_id: src.file_id, - ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), - }; - let parent_module = Module::from_definition(db, src_parent)?; + pub fn from_declaration(db: &impl DefDatabase, src: Source) -> Option { + let parent_declaration = src.ast.syntax().ancestors().skip(1).find_map(ast::Module::cast); + + let parent_module = match parent_declaration { + Some(parent_declaration) => { + let src_parent = Source { file_id: src.file_id, ast: parent_declaration }; + Module::from_declaration(db, src_parent) + } + _ => { + let src_parent = Source { + file_id: src.file_id, + ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), + }; + Module::from_definition(db, src_parent) + } + }?; + let child_name = src.ast.name()?; parent_module.child(db, &child_name.as_name()) } - pub fn from_definition( - db: &(impl DefDatabase + AstDatabase), - src: Source, - ) -> Option { - let decl_id = match src.ast { + pub fn from_definition(db: &impl DefDatabase, src: Source) -> Option { + match src.ast { ModuleSource::Module(ref module) => { assert!(!module.has_semi()); - let ast_id_map = db.ast_id_map(src.file_id); - let item_id = AstId::new(src.file_id, ast_id_map.ast_id(module)); - Some(item_id) + return Module::from_declaration( + db, + Source { file_id: src.file_id, ast: module.clone() }, + ); } - ModuleSource::SourceFile(_) => None, + ModuleSource::SourceFile(_) => (), }; - db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| { - let def_map = db.crate_def_map(crate_id); - - let (module_id, _module_data) = - def_map.modules.iter().find(|(_module_id, module_data)| { - if decl_id.is_some() { - module_data.declaration == decl_id - } else { - module_data.definition.map(|it| it.into()) == Some(src.file_id) - } - })?; + let original_file = src.file_id.original_file(db); - Some(Module::new(Crate { crate_id }, module_id)) - }) + let (krate, module_id) = + db.relevant_crates(original_file).iter().find_map(|&crate_id| { + let crate_def_map = db.crate_def_map(crate_id); + let local_module_id = crate_def_map.modules_for_file(original_file).next()?; + Some((crate_id, local_module_id)) + })?; + Some(Module { id: ModuleId { krate, module_id } }) } } -- cgit v1.2.3 From a28907af8ca93077601053cf168ac2429855c394 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 10:42:54 +0300 Subject: Privatize modules --- crates/ra_hir/src/test_db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs index 5237b303a..1caa2e875 100644 --- a/crates/ra_hir/src/test_db.rs +++ b/crates/ra_hir/src/test_db.rs @@ -81,7 +81,7 @@ impl TestDB { let crate_graph = self.crate_graph(); for krate in crate_graph.iter().next() { let crate_def_map = self.crate_def_map(krate); - for (module_id, _) in crate_def_map.modules.iter() { + for module_id in crate_def_map.modules() { let module_id = ModuleId { krate, module_id }; let module = crate::Module::from(module_id); module.diagnostics( -- cgit v1.2.3 From b80fa14a850db78b1f45de95b0edde1a65da4625 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 12:00:36 +0300 Subject: Use Local more --- crates/ra_hir/src/expr.rs | 2 +- crates/ra_hir/src/resolve.rs | 17 ++++++++++------- crates/ra_hir/src/source_binder.rs | 8 -------- 3 files changed, 11 insertions(+), 16 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 9262325f2..899e0fa04 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -38,7 +38,7 @@ pub(crate) fn resolver_for_scope( let scopes = owner.expr_scopes(db); let scope_chain = scopes.scope_chain(scope_id).collect::>(); for scope in scope_chain.into_iter().rev() { - r = r.push_expr_scope(Arc::clone(&scopes), scope); + r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); } r } diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 2f3e12eb8..b922fe20f 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -16,8 +16,8 @@ use crate::{ expr::{ExprScopes, PatId, ScopeId}, generics::GenericParams, impl_block::ImplBlock, - Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, - TypeAlias, + Adt, Const, DefWithBody, Enum, EnumVariant, Function, Local, MacroDef, ModuleDef, PerNs, + Static, Struct, Trait, TypeAlias, }; #[derive(Debug, Clone, Default)] @@ -34,6 +34,7 @@ pub(crate) struct ModuleItemMap { #[derive(Debug, Clone)] pub(crate) struct ExprScope { + owner: DefWithBody, expr_scopes: Arc, scope_id: ScopeId, } @@ -399,10 +400,11 @@ impl Resolver { pub(crate) fn push_expr_scope( self, + owner: DefWithBody, expr_scopes: Arc, scope_id: ScopeId, ) -> Resolver { - self.push_scope(Scope::ExprScope(ExprScope { expr_scopes, scope_id })) + self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) } } @@ -413,7 +415,7 @@ pub enum ScopeDef { GenericParam(u32), ImplSelfType(ImplBlock), AdtSelfType(Adt), - LocalBinding(PatId), + Local(Local), Unknown, } @@ -467,9 +469,10 @@ impl Scope { Scope::AdtScope(i) => { f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i)); } - Scope::ExprScope(e) => { - e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { - f(e.name().clone(), ScopeDef::LocalBinding(e.pat())); + Scope::ExprScope(scope) => { + scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { + let local = Local { parent: scope.owner, pat_id: e.pat() }; + f(e.name().clone(), ScopeDef::Local(local)); }); } } diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index ca40e3b54..59046edcc 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -195,14 +195,6 @@ impl SourceAnalyzer { Some(self.infer.as_ref()?[pat_id].clone()) } - pub fn type_of_pat_by_id( - &self, - _db: &impl HirDatabase, - pat_id: expr::PatId, - ) -> Option { - Some(self.infer.as_ref()?[pat_id].clone()) - } - pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { let expr_id = self.expr_id(&call.clone().into())?; self.infer.as_ref()?.method_resolution(expr_id) -- cgit v1.2.3 From 487fc448c3fae2f494f0e5a9e208aa012cfb6309 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 12:24:30 +0300 Subject: Reduce visibility --- crates/ra_hir/src/resolve.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index b922fe20f..2fb913108 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -54,7 +54,7 @@ pub(crate) enum Scope { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum TypeNs { +pub(crate) enum TypeNs { SelfType(ImplBlock), GenericParam(u32), Adt(Adt), @@ -69,13 +69,13 @@ pub enum TypeNs { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ResolveValueResult { +pub(crate) enum ResolveValueResult { ValueNs(ValueNs), Partial(TypeNs, usize), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ValueNs { +pub(crate) enum ValueNs { LocalBinding(PatId), Function(Function), Const(Const), -- cgit v1.2.3 From 3564fbb7f5fc7fc91530c441a6dacce88762fcc9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 12:56:24 +0300 Subject: Auto-upgrade some insta snapshots --- crates/ra_hir/src/ty/tests.rs | 54 ++++--------------------------------------- 1 file changed, 5 insertions(+), 49 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 8863c3608..fe9346c78 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -254,7 +254,6 @@ fn test(a: u32, b: isize, c: !, d: &str) { 1.0f32; }"#), @r###" - [9; 10) 'a': u32 [17; 18) 'b': isize [27; 28) 'c': ! @@ -317,7 +316,6 @@ fn test() { } "#), @r###" - [15; 20) '{ 1 }': u32 [17; 18) '1': u32 [48; 53) '{ 1 }': u32 @@ -354,7 +352,7 @@ fn test() { [66; 74) 'S::foo()': i32 [80; 88) '::foo': fn foo() -> i32 [80; 90) '::foo()': i32 -"### + "### ); } @@ -409,7 +407,6 @@ fn test() { } "#), @r###" - [72; 154) '{ ...a.c; }': () [82; 83) 'c': C [86; 87) 'C': C(usize) -> C @@ -443,7 +440,6 @@ fn test() { E::V2; }"#), @r###" - [48; 82) '{ E:...:V2; }': () [52; 70) 'E::V1 ...d: 1 }': E [67; 68) '1': u32 @@ -471,7 +467,6 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { } "#), @r###" - [9; 10) 'a': &u32 [18; 19) 'b': &mut u32 [31; 32) 'c': *const u32 @@ -524,7 +519,6 @@ fn test() { } "##), @r###" - [11; 221) '{ ...o"#; }': () [17; 21) '5i32': i32 [27; 31) '5f32': f32 @@ -568,7 +562,6 @@ fn test(x: SomeType) { } "#), @r###" - [27; 28) 'x': SomeType [40; 272) '{ ...lo"; }': () [50; 51) 'b': bool @@ -632,7 +625,6 @@ fn test() -> &mut &f64 { } "#), @r###" - [14; 15) 'x': u32 [22; 24) '{}': () [78; 231) '{ ...t &c }': &mut &f64 @@ -679,7 +671,6 @@ impl S { } "#), @r###" - [34; 38) 'self': &S [40; 61) '{ ... }': () [50; 54) 'self': &S @@ -719,7 +710,6 @@ fn test() -> bool { } "#), @r###" - [6; 7) 'x': bool [22; 34) '{ 0i32 }': i32 [28; 32) '0i32': i32 @@ -802,7 +792,6 @@ fn test2(a1: *const A, a2: *mut A) { } "#), @r###" - [44; 45) 'a': A [50; 213) '{ ...5.b; }': () [60; 62) 'a1': A @@ -970,7 +959,7 @@ fn test(a: A) { [374; 375) 'B': B>(T) -> B [374; 378) 'B(a)': B> [376; 377) 'a': A -"### + "### ); } @@ -983,7 +972,6 @@ fn test() { } "#), @r###" - [11; 37) '{ l... {}; }': () [20; 21) 'x': () [24; 34) 'if true {}': () @@ -1105,7 +1093,6 @@ fn test(a: A) { } "#), @r###" - [32; 36) 'self': A [38; 39) 'x': u32 [53; 55) '{}': () @@ -1142,7 +1129,6 @@ fn test() { } "#), @r###" - [40; 44) 'self': &str [53; 55) '{}': () [69; 89) '{ ...o(); }': () @@ -1166,7 +1152,6 @@ fn test(x: &str, y: isize) { } "#), @r###" - [9; 10) 'x': &str [18; 19) 'y': isize [28; 170) '{ ...d"); }': () @@ -1367,7 +1352,6 @@ fn test() { } "#), @r###" - [28; 79) '{ ...(1); }': () [38; 42) 'A(n)': A [40; 41) 'n': &i32 @@ -1396,7 +1380,6 @@ fn test() { } "#), @r###" - [11; 57) '{ ...= v; }': () [21; 22) 'v': &(i32, &i32) [25; 33) '&(1, &2)': &(i32, &i32) @@ -1441,7 +1424,6 @@ fn test() { } "#), @r###" - [68; 289) '{ ... d; }': () [78; 79) 'e': E [82; 95) 'E::A { x: 3 }': E @@ -1488,7 +1470,6 @@ fn test(a1: A, i: i32) { } "#), @r###" - [36; 38) 'a1': A [48; 49) 'i': i32 [56; 147) '{ ...3.x; }': () @@ -1569,7 +1550,6 @@ fn test(a1: A, o: Option) { } "#), @r###" - [79; 81) 'a1': A [91; 92) 'o': Option [107; 244) '{ ... }; }': () @@ -1604,7 +1584,6 @@ fn test() { } "#), @r###" - [10; 11) 't': T [21; 26) '{ t }': T [23; 24) 't': T @@ -1652,7 +1631,6 @@ fn test() -> i128 { } "#), @r###" - [74; 78) 'self': A [85; 107) '{ ... }': X [95; 99) 'self': A @@ -1706,7 +1684,6 @@ fn test(o: Option) { } "#), @r###" - [78; 82) 'self': &Option [98; 100) '{}': () [111; 112) 'o': Option @@ -1744,7 +1721,6 @@ fn test() -> i128 { } "#), @r###" - [53; 57) 'self': A [65; 87) '{ ... }': T2 [75; 79) 'self': A @@ -1921,7 +1897,6 @@ fn test() { } "#), @r###" - [56; 64) '{ A {} }': A [58; 62) 'A {}': A [126; 132) '{ 99 }': u32 @@ -1961,7 +1936,6 @@ fn test() { } "#), @r###" - [64; 67) 'val': T [82; 109) '{ ... }': Gen [92; 103) 'Gen { val }': Gen @@ -2129,7 +2103,6 @@ fn test(x: X) { } "#), @r###" - [20; 21) 'x': X [26; 47) '{ ...eld; }': () [32; 33) 'x': X @@ -2151,7 +2124,6 @@ fn test() { } "#), @r###" - [11; 89) '{ ... } }': () [17; 21) 'X {}': {unknown} [27; 87) 'match ... }': () @@ -2174,7 +2146,6 @@ fn quux() { } "#), @r###" - [11; 41) '{ ...+ y; }': () [21; 22) 'y': i32 [25; 27) '92': i32 @@ -2300,7 +2271,6 @@ fn write() { } "#), @r###" - [54; 139) '{ ... } }': () [60; 137) 'match ... }': () [66; 83) 'someth...nknown': Maybe<{unknown}> @@ -2322,7 +2292,6 @@ fn test_line_buffer() { } "#), @r###" - [23; 53) '{ ...n']; }': () [29; 50) '&[0, b...b'\n']': &[u8;_] [30; 50) '[0, b'...b'\n']': [u8;_] @@ -2446,7 +2415,6 @@ fn test(query_response: Canonical>) { } "#), @r###" - [92; 106) 'query_response': Canonical> [137; 167) '{ ...lue; }': () [143; 164) '&query....value': &QueryResponse @@ -2472,7 +2440,6 @@ pub fn main_loop() { } "#), @r###" - [144; 146) '{}': () [169; 198) '{ ...t(); }': () [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet @@ -2518,7 +2485,6 @@ fn test() { } "#), @r###" - [49; 50) '0': u32 [80; 83) '101': u32 [95; 213) '{ ...NST; }': () @@ -2549,7 +2515,6 @@ fn test() { } "#), @r###" - [29; 32) '101': u32 [70; 73) '101': u32 [85; 280) '{ ...MUT; }': () @@ -2588,7 +2553,6 @@ fn test() { } "#), @r###" - [31; 35) 'self': &Self [110; 114) 'self': &Self [170; 228) '{ ...i128 }': () @@ -2636,7 +2600,6 @@ mod bar_test { } "#), @r###" - [63; 67) 'self': &Self [169; 173) 'self': &Self [300; 337) '{ ... }': () @@ -2664,7 +2627,6 @@ fn test() { } "#), @r###" - [33; 37) 'self': &Self [92; 111) '{ ...d(); }': () [98; 99) 'S': S @@ -2694,7 +2656,6 @@ fn test() { } "#), @r###" - [43; 47) 'self': &Self [82; 86) 'self': &Self [210; 361) '{ ..., i8 }': () @@ -2725,7 +2686,6 @@ fn test() { } "#), @r###" - [33; 37) 'self': &Self [102; 127) '{ ...d(); }': () [108; 109) 'S': S(T) -> S @@ -3130,7 +3090,6 @@ fn test>() { } "#), @r###" - [67; 100) '{ ...own; }': () [77; 78) 'y': {unknown} [90; 97) 'unknown': {unknown} @@ -3146,7 +3105,6 @@ const A: u32 = 1 + 1; static B: u64 = { let x = 1; x }; "#), @r###" - [16; 17) '1': u32 [16; 21) '1 + 1': u32 [20; 21) '1': u32 @@ -3170,7 +3128,6 @@ fn test() -> u64 { } "#), @r###" - [38; 87) '{ ... a.1 }': u64 [48; 49) 'a': S [52; 53) 'S': S(i32, u64) -> S @@ -3225,7 +3182,6 @@ fn indexing_arrays() { assert_snapshot!( infer("fn main() { &mut [9][2]; }"), @r###" - [10; 26) '{ &mut...[2]; }': () [12; 23) '&mut [9][2]': &mut {unknown} [17; 20) '[9]': [i32;_] @@ -4822,9 +4778,9 @@ fn main() { } "#), @r###" - ![0; 1) '6': i32 - [64; 88) '{ ...!(); }': () - [74; 75) 'x': i32 + ![0; 1) '6': i32 + [64; 88) '{ ...!(); }': () + [74; 75) 'x': i32 "### ); } -- cgit v1.2.3 From 9167da66acff22b4fe68d7bbe60c25ab0b56ad72 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 14:15:04 +0300 Subject: Reduce visibility --- crates/ra_hir/src/source_binder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 59046edcc..c1ecf18b9 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -285,7 +285,7 @@ impl SourceAnalyzer { self.resolve_hir_path(db, &hir_path) } - pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option { + fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option { let mut shadowed = FxHashSet::default(); let name = name_ref.as_name(); let source_map = self.body_source_map.as_ref()?; @@ -309,9 +309,9 @@ impl SourceAnalyzer { self.resolver.process_all_names(db, f) } + // FIXME: we only use this in `inline_local_variable` assist, ideally, we + // should switch to general reference search infra there. pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec { - // FIXME: at least, this should work with any DefWithBody, but ideally - // this should be hir-based altogether let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone()))); fn_def -- cgit v1.2.3 From 2f6c0c314b749e25431f3fd6caaac5d3270751b6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 14:47:26 +0300 Subject: Move scope tests to hir_def --- crates/ra_hir/src/expr.rs | 189 ------------------------------------- crates/ra_hir/src/source_binder.rs | 24 +---- 2 files changed, 5 insertions(+), 208 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 899e0fa04..e4598eec0 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -42,192 +42,3 @@ pub(crate) fn resolver_for_scope( } r } - -#[cfg(test)] -mod tests { - use hir_expand::Source; - use ra_db::{fixture::WithFixture, SourceDatabase}; - use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; - use test_utils::{assert_eq_text, extract_offset}; - - use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; - - fn do_check(code: &str, expected: &[&str]) { - let (off, code) = extract_offset(code); - let code = { - let mut buf = String::new(); - let off = u32::from(off) as usize; - buf.push_str(&code[..off]); - buf.push_str("marker"); - buf.push_str(&code[off..]); - buf - }; - - let (db, file_id) = TestDB::with_single_file(&code); - - let file = db.parse(file_id).ok().unwrap(); - let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); - let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); - - let scopes = analyzer.scopes(); - let expr_id = analyzer - .body_source_map() - .node_expr(Source { file_id: file_id.into(), ast: &marker.into() }) - .unwrap(); - let scope = scopes.scope_for(expr_id); - - let actual = scopes - .scope_chain(scope) - .flat_map(|scope| scopes.entries(scope)) - .map(|it| it.name().to_string()) - .collect::>() - .join("\n"); - let expected = expected.join("\n"); - assert_eq_text!(&expected, &actual); - } - - #[test] - fn test_lambda_scope() { - do_check( - r" - fn quux(foo: i32) { - let f = |bar, baz: i32| { - <|> - }; - }", - &["bar", "baz", "foo"], - ); - } - - #[test] - fn test_call_scope() { - do_check( - r" - fn quux() { - f(|x| <|> ); - }", - &["x"], - ); - } - - #[test] - fn test_method_call_scope() { - do_check( - r" - fn quux() { - z.f(|x| <|> ); - }", - &["x"], - ); - } - - #[test] - fn test_loop_scope() { - do_check( - r" - fn quux() { - loop { - let x = (); - <|> - }; - }", - &["x"], - ); - } - - #[test] - fn test_match() { - do_check( - r" - fn quux() { - match () { - Some(x) => { - <|> - } - }; - }", - &["x"], - ); - } - - #[test] - fn test_shadow_variable() { - do_check( - r" - fn foo(x: String) { - let x : &str = &x<|>; - }", - &["x"], - ); - } - - fn do_check_local_name(code: &str, expected_offset: u32) { - let (off, code) = extract_offset(code); - - let (db, file_id) = TestDB::with_single_file(&code); - let file = db.parse(file_id).ok().unwrap(); - let expected_name = find_node_at_offset::(file.syntax(), expected_offset.into()) - .expect("failed to find a name at the target offset"); - let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); - let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); - - let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); - let local_name = - local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); - assert_eq!(local_name.range(), expected_name.syntax().text_range()); - } - - #[test] - fn test_resolve_local_name() { - do_check_local_name( - r#" - fn foo(x: i32, y: u32) { - { - let z = x * 2; - } - { - let t = x<|> * 3; - } - }"#, - 21, - ); - } - - #[test] - fn test_resolve_local_name_declaration() { - do_check_local_name( - r#" - fn foo(x: String) { - let x : &str = &x<|>; - }"#, - 21, - ); - } - - #[test] - fn test_resolve_local_name_shadow() { - do_check_local_name( - r" - fn foo(x: String) { - let x : &str = &x; - x<|> - } - ", - 53, - ); - } - - #[test] - fn ref_patterns_contribute_bindings() { - do_check_local_name( - r" - fn foo() { - if let Some(&from) = bar() { - from<|>; - } - } - ", - 53, - ); - } -} diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c1ecf18b9..662d3f880 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -19,7 +19,6 @@ use ra_syntax::{ SyntaxKind::*, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, }; -use rustc_hash::FxHashSet; use crate::{ db::HirDatabase, @@ -286,22 +285,14 @@ impl SourceAnalyzer { } fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option { - let mut shadowed = FxHashSet::default(); let name = name_ref.as_name(); let source_map = self.body_source_map.as_ref()?; let scopes = self.scopes.as_ref()?; - let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); - let ret = scopes - .scope_chain(scope) - .flat_map(|scope| scopes.entries(scope).iter()) - .filter(|entry| shadowed.insert(entry.name())) - .filter(|entry| entry.name() == &name) - .nth(0); - ret.and_then(|entry| { - Some(ScopeEntryWithSyntax { - name: entry.name().clone(), - ptr: source_map.pat_syntax(entry.pat())?.ast, - }) + let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?; + let entry = scopes.resolve_name_in_scope(scope, &name)?; + Some(ScopeEntryWithSyntax { + name: entry.name().clone(), + ptr: source_map.pat_syntax(entry.pat())?.ast, }) } @@ -413,11 +404,6 @@ impl SourceAnalyzer { pub(crate) fn inference_result(&self) -> Arc { self.infer.clone().unwrap() } - - #[cfg(test)] - pub(crate) fn scopes(&self) -> Arc { - self.scopes.clone().unwrap() - } } fn scope_for( -- cgit v1.2.3 From c3f84960aa99529a3afc8f28c16e657fb071db5f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 15 Nov 2019 14:53:09 +0300 Subject: Flatten expr module --- crates/ra_hir/src/code_model.rs | 2 +- crates/ra_hir/src/expr.rs | 132 ++++++++++++++++++++++++++++++++- crates/ra_hir/src/expr/validation.rs | 137 ----------------------------------- 3 files changed, 130 insertions(+), 141 deletions(-) delete mode 100644 crates/ra_hir/src/expr/validation.rs (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index dd43271f4..078bd8609 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -23,7 +23,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, - expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, + expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId}, generics::{GenericDef, HasGenericParams}, ids::{ AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index e4598eec0..e3733779e 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -1,12 +1,19 @@ //! FIXME: write short doc here -pub(crate) mod validation; - use std::sync::Arc; +use hir_def::path::known; +use hir_expand::diagnostics::DiagnosticSink; +use ra_syntax::ast; use ra_syntax::AstPtr; +use rustc_hash::FxHashSet; -use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; +use crate::{ + db::HirDatabase, + diagnostics::{MissingFields, MissingOkInTailExpr}, + ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, + Adt, DefWithBody, Function, HasBody, Name, Path, Resolver, +}; pub use hir_def::{ body::{ @@ -42,3 +49,122 @@ pub(crate) fn resolver_for_scope( } r } + +pub(crate) struct ExprValidator<'a, 'b: 'a> { + func: Function, + infer: Arc, + sink: &'a mut DiagnosticSink<'b>, +} + +impl<'a, 'b> ExprValidator<'a, 'b> { + pub(crate) fn new( + func: Function, + infer: Arc, + sink: &'a mut DiagnosticSink<'b>, + ) -> ExprValidator<'a, 'b> { + ExprValidator { func, infer, sink } + } + + pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { + let body = self.func.body(db); + + for e in body.exprs() { + if let (id, Expr::RecordLit { path, fields, spread }) = e { + self.validate_record_literal(id, path, fields, *spread, db); + } + } + + let body_expr = &body[body.body_expr()]; + if let Expr::Block { statements: _, tail: Some(t) } = body_expr { + self.validate_results_in_tail_expr(body.body_expr(), *t, db); + } + } + + fn validate_record_literal( + &mut self, + id: ExprId, + _path: &Option, + fields: &[RecordLitField], + spread: Option, + db: &impl HirDatabase, + ) { + if spread.is_some() { + return; + } + + let struct_def = match self.infer[id].as_adt() { + Some((Adt::Struct(s), _)) => s, + _ => return, + }; + + let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); + let missed_fields: Vec = struct_def + .fields(db) + .iter() + .filter_map(|f| { + let name = f.name(db); + if lit_fields.contains(&name) { + None + } else { + Some(name) + } + }) + .collect(); + if missed_fields.is_empty() { + return; + } + let source_map = self.func.body_source_map(db); + + if let Some(source_ptr) = source_map.expr_syntax(id) { + if let Some(expr) = source_ptr.ast.a() { + let root = source_ptr.file_syntax(db); + if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { + if let Some(field_list) = record_lit.record_field_list() { + self.sink.push(MissingFields { + file: source_ptr.file_id, + field_list: AstPtr::new(&field_list), + missed_fields, + }) + } + } + } + } + } + + fn validate_results_in_tail_expr( + &mut self, + body_id: ExprId, + id: ExprId, + db: &impl HirDatabase, + ) { + // the mismatch will be on the whole block currently + let mismatch = match self.infer.type_mismatch_for_expr(body_id) { + Some(m) => m, + None => return, + }; + + let std_result_path = known::std_result_result(); + + let resolver = self.func.resolver(db); + let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { + Some(it) => it, + _ => return, + }; + + let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum)); + let params = match &mismatch.expected { + Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, + _ => return, + }; + + if params.len() == 2 && ¶ms[0] == &mismatch.actual { + let source_map = self.func.body_source_map(db); + + if let Some(source_ptr) = source_map.expr_syntax(id) { + if let Some(expr) = source_ptr.ast.a() { + self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); + } + } + } + } +} diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs deleted file mode 100644 index 3054f1dce..000000000 --- a/crates/ra_hir/src/expr/validation.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! FIXME: write short doc here - -use std::sync::Arc; - -use hir_def::path::known; -use hir_expand::diagnostics::DiagnosticSink; -use ra_syntax::ast; -use rustc_hash::FxHashSet; - -use crate::{ - db::HirDatabase, - diagnostics::{MissingFields, MissingOkInTailExpr}, - expr::AstPtr, - ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, - Adt, Function, Name, Path, -}; - -use super::{Expr, ExprId, RecordLitField}; - -pub(crate) struct ExprValidator<'a, 'b: 'a> { - func: Function, - infer: Arc, - sink: &'a mut DiagnosticSink<'b>, -} - -impl<'a, 'b> ExprValidator<'a, 'b> { - pub(crate) fn new( - func: Function, - infer: Arc, - sink: &'a mut DiagnosticSink<'b>, - ) -> ExprValidator<'a, 'b> { - ExprValidator { func, infer, sink } - } - - pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) { - let body = self.func.body(db); - - for e in body.exprs() { - if let (id, Expr::RecordLit { path, fields, spread }) = e { - self.validate_record_literal(id, path, fields, *spread, db); - } - } - - let body_expr = &body[body.body_expr()]; - if let Expr::Block { statements: _, tail: Some(t) } = body_expr { - self.validate_results_in_tail_expr(body.body_expr(), *t, db); - } - } - - fn validate_record_literal( - &mut self, - id: ExprId, - _path: &Option, - fields: &[RecordLitField], - spread: Option, - db: &impl HirDatabase, - ) { - if spread.is_some() { - return; - } - - let struct_def = match self.infer[id].as_adt() { - Some((Adt::Struct(s), _)) => s, - _ => return, - }; - - let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); - let missed_fields: Vec = struct_def - .fields(db) - .iter() - .filter_map(|f| { - let name = f.name(db); - if lit_fields.contains(&name) { - None - } else { - Some(name) - } - }) - .collect(); - if missed_fields.is_empty() { - return; - } - let source_map = self.func.body_source_map(db); - - if let Some(source_ptr) = source_map.expr_syntax(id) { - if let Some(expr) = source_ptr.ast.a() { - let root = source_ptr.file_syntax(db); - if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { - if let Some(field_list) = record_lit.record_field_list() { - self.sink.push(MissingFields { - file: source_ptr.file_id, - field_list: AstPtr::new(&field_list), - missed_fields, - }) - } - } - } - } - } - - fn validate_results_in_tail_expr( - &mut self, - body_id: ExprId, - id: ExprId, - db: &impl HirDatabase, - ) { - // the mismatch will be on the whole block currently - let mismatch = match self.infer.type_mismatch_for_expr(body_id) { - Some(m) => m, - None => return, - }; - - let std_result_path = known::std_result_result(); - - let resolver = self.func.resolver(db); - let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { - Some(it) => it, - _ => return, - }; - - let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum)); - let params = match &mismatch.expected { - Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, - _ => return, - }; - - if params.len() == 2 && ¶ms[0] == &mismatch.actual { - let source_map = self.func.body_source_map(db); - - if let Some(source_ptr) = source_map.expr_syntax(id) { - if let Some(expr) = source_ptr.ast.a() { - self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); - } - } - } - } -} -- cgit v1.2.3