aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/scope/fn_scope.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-10-31 18:03:00 +0000
committerAleksey Kladov <[email protected]>2018-10-31 18:03:00 +0000
commitc09e14a4ff02f774460a70472e1aeb3c598e01dc (patch)
tree8100886e13a79b5c948a0273b761806d3ff57c3d /crates/ra_editor/src/scope/fn_scope.rs
parentf3fb59d7077801a3a68d2d03eef17d59c2925ae8 (diff)
remove old completion
Diffstat (limited to 'crates/ra_editor/src/scope/fn_scope.rs')
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs363
1 files changed, 0 insertions, 363 deletions
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
deleted file mode 100644
index 4cb1f077c..000000000
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ /dev/null
@@ -1,363 +0,0 @@
1use std::fmt;
2
3use rustc_hash::FxHashMap;
4
5use ra_syntax::{
6 algo::generate,
7 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
8 AstNode, SmolStr, SyntaxNode, SyntaxNodeRef,
9};
10
11type ScopeId = usize;
12
13#[derive(Debug)]
14pub struct FnScopes {
15 pub self_param: Option<SyntaxNode>,
16 scopes: Vec<ScopeData>,
17 scope_for: FxHashMap<SyntaxNode, ScopeId>,
18}
19
20impl FnScopes {
21 pub fn new(fn_def: ast::FnDef) -> FnScopes {
22 let mut scopes = FnScopes {
23 self_param: fn_def
24 .param_list()
25 .and_then(|it| it.self_param())
26 .map(|it| it.syntax().owned()),
27 scopes: Vec::new(),
28 scope_for: FxHashMap::default(),
29 };
30 let root = scopes.root_scope();
31 scopes.add_params_bindings(root, fn_def.param_list());
32 if let Some(body) = fn_def.body() {
33 compute_block_scopes(body, &mut scopes, root)
34 }
35 scopes
36 }
37 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
38 &self.scopes[scope].entries
39 }
40 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
41 generate(self.scope_for(node), move |&scope| {
42 self.scopes[scope].parent
43 })
44 }
45 fn root_scope(&mut self) -> ScopeId {
46 let res = self.scopes.len();
47 self.scopes.push(ScopeData {
48 parent: None,
49 entries: vec![],
50 });
51 res
52 }
53 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
54 let res = self.scopes.len();
55 self.scopes.push(ScopeData {
56 parent: Some(parent),
57 entries: vec![],
58 });
59 res
60 }
61 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
62 let entries = pat
63 .syntax()
64 .descendants()
65 .filter_map(ast::BindPat::cast)
66 .filter_map(ScopeEntry::new);
67 self.scopes[scope].entries.extend(entries);
68 }
69 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
70 params
71 .into_iter()
72 .flat_map(|it| it.params())
73 .filter_map(|it| it.pat())
74 .for_each(|it| self.add_bindings(scope, it));
75 }
76 fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
77 self.scope_for.insert(node.owned(), scope);
78 }
79 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
80 node.ancestors()
81 .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
82 .next()
83 }
84}
85
86#[derive(PartialEq, Eq)]
87pub struct ScopeEntry {
88 syntax: SyntaxNode,
89}
90
91impl ScopeEntry {
92 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
93 if pat.name().is_some() {
94 Some(ScopeEntry {
95 syntax: pat.syntax().owned(),
96 })
97 } else {
98 None
99 }
100 }
101 pub fn name(&self) -> SmolStr {
102 self.ast().name().unwrap().text()
103 }
104 pub fn ast(&self) -> ast::BindPat {
105 ast::BindPat::cast(self.syntax.borrowed()).unwrap()
106 }
107}
108
109impl fmt::Debug for ScopeEntry {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 f.debug_struct("ScopeEntry")
112 .field("name", &self.name())
113 .field("syntax", &self.syntax)
114 .finish()
115 }
116}
117
118fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
119 for stmt in block.statements() {
120 match stmt {
121 ast::Stmt::LetStmt(stmt) => {
122 if let Some(expr) = stmt.initializer() {
123 scopes.set_scope(expr.syntax(), scope);
124 compute_expr_scopes(expr, scopes, scope);
125 }
126 scope = scopes.new_scope(scope);
127 if let Some(pat) = stmt.pat() {
128 scopes.add_bindings(scope, pat);
129 }
130 }
131 ast::Stmt::ExprStmt(expr_stmt) => {
132 if let Some(expr) = expr_stmt.expr() {
133 scopes.set_scope(expr.syntax(), scope);
134 compute_expr_scopes(expr, scopes, scope);
135 }
136 }
137 }
138 }
139 if let Some(expr) = block.expr() {
140 scopes.set_scope(expr.syntax(), scope);
141 compute_expr_scopes(expr, scopes, scope);
142 }
143}
144
145fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
146 match expr {
147 ast::Expr::IfExpr(e) => {
148 let cond_scope = e
149 .condition()
150 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
151 if let Some(block) = e.then_branch() {
152 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
153 }
154 if let Some(block) = e.else_branch() {
155 compute_block_scopes(block, scopes, scope);
156 }
157 }
158 ast::Expr::BlockExpr(e) => {
159 if let Some(block) = e.block() {
160 compute_block_scopes(block, scopes, scope);
161 }
162 }
163 ast::Expr::LoopExpr(e) => {
164 if let Some(block) = e.loop_body() {
165 compute_block_scopes(block, scopes, scope);
166 }
167 }
168 ast::Expr::WhileExpr(e) => {
169 let cond_scope = e
170 .condition()
171 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
172 if let Some(block) = e.loop_body() {
173 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
174 }
175 }
176 ast::Expr::ForExpr(e) => {
177 if let Some(expr) = e.iterable() {
178 compute_expr_scopes(expr, scopes, scope);
179 }
180 let mut scope = scope;
181 if let Some(pat) = e.pat() {
182 scope = scopes.new_scope(scope);
183 scopes.add_bindings(scope, pat);
184 }
185 if let Some(block) = e.loop_body() {
186 compute_block_scopes(block, scopes, scope);
187 }
188 }
189 ast::Expr::LambdaExpr(e) => {
190 let scope = scopes.new_scope(scope);
191 scopes.add_params_bindings(scope, e.param_list());
192 if let Some(body) = e.body() {
193 scopes.set_scope(body.syntax(), scope);
194 compute_expr_scopes(body, scopes, scope);
195 }
196 }
197 ast::Expr::CallExpr(e) => {
198 compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
199 }
200 ast::Expr::MethodCallExpr(e) => {
201 compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
202 }
203 ast::Expr::MatchExpr(e) => {
204 if let Some(expr) = e.expr() {
205 compute_expr_scopes(expr, scopes, scope);
206 }
207 for arm in e.match_arm_list().into_iter().flat_map(|it| it.arms()) {
208 let scope = scopes.new_scope(scope);
209 for pat in arm.pats() {
210 scopes.add_bindings(scope, pat);
211 }
212 if let Some(expr) = arm.expr() {
213 compute_expr_scopes(expr, scopes, scope);
214 }
215 }
216 }
217 _ => expr
218 .syntax()
219 .children()
220 .filter_map(ast::Expr::cast)
221 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
222 };
223
224 fn compute_call_scopes(
225 receiver: Option<ast::Expr>,
226 arg_list: Option<ast::ArgList>,
227 scopes: &mut FnScopes,
228 scope: ScopeId,
229 ) {
230 arg_list
231 .into_iter()
232 .flat_map(|it| it.args())
233 .chain(receiver)
234 .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
235 }
236
237 fn compute_cond_scopes(
238 cond: ast::Condition,
239 scopes: &mut FnScopes,
240 scope: ScopeId,
241 ) -> Option<ScopeId> {
242 if let Some(expr) = cond.expr() {
243 compute_expr_scopes(expr, scopes, scope);
244 }
245 if let Some(pat) = cond.pat() {
246 let s = scopes.new_scope(scope);
247 scopes.add_bindings(s, pat);
248 Some(s)
249 } else {
250 None
251 }
252 }
253}
254
255#[derive(Debug, PartialEq, Eq)]
256struct ScopeData {
257 parent: Option<ScopeId>,
258 entries: Vec<ScopeEntry>,
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264 use crate::{find_node_at_offset, test_utils::extract_offset};
265 use ra_syntax::File;
266
267 fn do_check(code: &str, expected: &[&str]) {
268 let (off, code) = extract_offset(code);
269 let code = {
270 let mut buf = String::new();
271 let off = u32::from(off) as usize;
272 buf.push_str(&code[..off]);
273 buf.push_str("marker");
274 buf.push_str(&code[off..]);
275 buf
276 };
277 let file = File::parse(&code);
278 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
279 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
280 let scopes = FnScopes::new(fn_def);
281 let actual = scopes
282 .scope_chain(marker.syntax())
283 .flat_map(|scope| scopes.entries(scope))
284 .map(|it| it.name())
285 .collect::<Vec<_>>();
286 assert_eq!(actual.as_slice(), expected);
287 }
288
289 #[test]
290 fn test_lambda_scope() {
291 do_check(
292 r"
293 fn quux(foo: i32) {
294 let f = |bar, baz: i32| {
295 <|>
296 };
297 }",
298 &["bar", "baz", "foo"],
299 );
300 }
301
302 #[test]
303 fn test_call_scope() {
304 do_check(
305 r"
306 fn quux() {
307 f(|x| <|> );
308 }",
309 &["x"],
310 );
311 }
312
313 #[test]
314 fn test_metod_call_scope() {
315 do_check(
316 r"
317 fn quux() {
318 z.f(|x| <|> );
319 }",
320 &["x"],
321 );
322 }
323
324 #[test]
325 fn test_loop_scope() {
326 do_check(
327 r"
328 fn quux() {
329 loop {
330 let x = ();
331 <|>
332 };
333 }",
334 &["x"],
335 );
336 }
337
338 #[test]
339 fn test_match() {
340 do_check(
341 r"
342 fn quux() {
343 match () {
344 Some(x) => {
345 <|>
346 }
347 };
348 }",
349 &["x"],
350 );
351 }
352
353 #[test]
354 fn test_shadow_variable() {
355 do_check(
356 r"
357 fn foo(x: String) {
358 let x : &str = &x<|>;
359 }",
360 &["x"],
361 );
362 }
363}