aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/expr.rs189
-rw-r--r--crates/ra_hir/src/source_binder.rs24
2 files changed, 5 insertions, 208 deletions
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(
42 } 42 }
43 r 43 r
44} 44}
45
46#[cfg(test)]
47mod tests {
48 use hir_expand::Source;
49 use ra_db::{fixture::WithFixture, SourceDatabase};
50 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
51 use test_utils::{assert_eq_text, extract_offset};
52
53 use crate::{source_binder::SourceAnalyzer, test_db::TestDB};
54
55 fn do_check(code: &str, expected: &[&str]) {
56 let (off, code) = extract_offset(code);
57 let code = {
58 let mut buf = String::new();
59 let off = u32::from(off) as usize;
60 buf.push_str(&code[..off]);
61 buf.push_str("marker");
62 buf.push_str(&code[off..]);
63 buf
64 };
65
66 let (db, file_id) = TestDB::with_single_file(&code);
67
68 let file = db.parse(file_id).ok().unwrap();
69 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
70 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None);
71
72 let scopes = analyzer.scopes();
73 let expr_id = analyzer
74 .body_source_map()
75 .node_expr(Source { file_id: file_id.into(), ast: &marker.into() })
76 .unwrap();
77 let scope = scopes.scope_for(expr_id);
78
79 let actual = scopes
80 .scope_chain(scope)
81 .flat_map(|scope| scopes.entries(scope))
82 .map(|it| it.name().to_string())
83 .collect::<Vec<_>>()
84 .join("\n");
85 let expected = expected.join("\n");
86 assert_eq_text!(&expected, &actual);
87 }
88
89 #[test]
90 fn test_lambda_scope() {
91 do_check(
92 r"
93 fn quux(foo: i32) {
94 let f = |bar, baz: i32| {
95 <|>
96 };
97 }",
98 &["bar", "baz", "foo"],
99 );
100 }
101
102 #[test]
103 fn test_call_scope() {
104 do_check(
105 r"
106 fn quux() {
107 f(|x| <|> );
108 }",
109 &["x"],
110 );
111 }
112
113 #[test]
114 fn test_method_call_scope() {
115 do_check(
116 r"
117 fn quux() {
118 z.f(|x| <|> );
119 }",
120 &["x"],
121 );
122 }
123
124 #[test]
125 fn test_loop_scope() {
126 do_check(
127 r"
128 fn quux() {
129 loop {
130 let x = ();
131 <|>
132 };
133 }",
134 &["x"],
135 );
136 }
137
138 #[test]
139 fn test_match() {
140 do_check(
141 r"
142 fn quux() {
143 match () {
144 Some(x) => {
145 <|>
146 }
147 };
148 }",
149 &["x"],
150 );
151 }
152
153 #[test]
154 fn test_shadow_variable() {
155 do_check(
156 r"
157 fn foo(x: String) {
158 let x : &str = &x<|>;
159 }",
160 &["x"],
161 );
162 }
163
164 fn do_check_local_name(code: &str, expected_offset: u32) {
165 let (off, code) = extract_offset(code);
166
167 let (db, file_id) = TestDB::with_single_file(&code);
168 let file = db.parse(file_id).ok().unwrap();
169 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
170 .expect("failed to find a name at the target offset");
171 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
172 let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None);
173
174 let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap();
175 let local_name =
176 local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
177 assert_eq!(local_name.range(), expected_name.syntax().text_range());
178 }
179
180 #[test]
181 fn test_resolve_local_name() {
182 do_check_local_name(
183 r#"
184 fn foo(x: i32, y: u32) {
185 {
186 let z = x * 2;
187 }
188 {
189 let t = x<|> * 3;
190 }
191 }"#,
192 21,
193 );
194 }
195
196 #[test]
197 fn test_resolve_local_name_declaration() {
198 do_check_local_name(
199 r#"
200 fn foo(x: String) {
201 let x : &str = &x<|>;
202 }"#,
203 21,
204 );
205 }
206
207 #[test]
208 fn test_resolve_local_name_shadow() {
209 do_check_local_name(
210 r"
211 fn foo(x: String) {
212 let x : &str = &x;
213 x<|>
214 }
215 ",
216 53,
217 );
218 }
219
220 #[test]
221 fn ref_patterns_contribute_bindings() {
222 do_check_local_name(
223 r"
224 fn foo() {
225 if let Some(&from) = bar() {
226 from<|>;
227 }
228 }
229 ",
230 53,
231 );
232 }
233}
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::{
19 SyntaxKind::*, 19 SyntaxKind::*,
20 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 20 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
21}; 21};
22use rustc_hash::FxHashSet;
23 22
24use crate::{ 23use crate::{
25 db::HirDatabase, 24 db::HirDatabase,
@@ -286,22 +285,14 @@ impl SourceAnalyzer {
286 } 285 }
287 286
288 fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { 287 fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> {
289 let mut shadowed = FxHashSet::default();
290 let name = name_ref.as_name(); 288 let name = name_ref.as_name();
291 let source_map = self.body_source_map.as_ref()?; 289 let source_map = self.body_source_map.as_ref()?;
292 let scopes = self.scopes.as_ref()?; 290 let scopes = self.scopes.as_ref()?;
293 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); 291 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?;
294 let ret = scopes 292 let entry = scopes.resolve_name_in_scope(scope, &name)?;
295 .scope_chain(scope) 293 Some(ScopeEntryWithSyntax {
296 .flat_map(|scope| scopes.entries(scope).iter()) 294 name: entry.name().clone(),
297 .filter(|entry| shadowed.insert(entry.name())) 295 ptr: source_map.pat_syntax(entry.pat())?.ast,
298 .filter(|entry| entry.name() == &name)
299 .nth(0);
300 ret.and_then(|entry| {
301 Some(ScopeEntryWithSyntax {
302 name: entry.name().clone(),
303 ptr: source_map.pat_syntax(entry.pat())?.ast,
304 })
305 }) 296 })
306 } 297 }
307 298
@@ -413,11 +404,6 @@ impl SourceAnalyzer {
413 pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> { 404 pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> {
414 self.infer.clone().unwrap() 405 self.infer.clone().unwrap()
415 } 406 }
416
417 #[cfg(test)]
418 pub(crate) fn scopes(&self) -> Arc<ExprScopes> {
419 self.scopes.clone().unwrap()
420 }
421} 407}
422 408
423fn scope_for( 409fn scope_for(