aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/gen_lsp_server/src/lib.rs35
-rw-r--r--crates/gen_lsp_server/src/msg.rs29
-rw-r--r--crates/gen_lsp_server/src/stdio.rs6
-rw-r--r--crates/ra_analysis/src/db.rs21
-rw-r--r--crates/ra_analysis/src/descriptors.rs108
-rw-r--r--crates/ra_analysis/src/imp.rs207
-rw-r--r--crates/ra_analysis/src/job.rs14
-rw-r--r--crates/ra_analysis/src/lib.rs78
-rw-r--r--crates/ra_analysis/src/module_map.rs13
-rw-r--r--crates/ra_analysis/src/roots.rs63
-rw-r--r--crates/ra_analysis/src/symbol_index.rs29
-rw-r--r--crates/ra_analysis/tests/tests.rs82
-rw-r--r--crates/ra_cli/src/main.rs27
-rw-r--r--crates/ra_editor/src/code_actions.rs49
-rw-r--r--crates/ra_editor/src/completion.rs178
-rw-r--r--crates/ra_editor/src/edit.rs13
-rw-r--r--crates/ra_editor/src/extend_selection.rs58
-rw-r--r--crates/ra_editor/src/folding_ranges.rs36
-rw-r--r--crates/ra_editor/src/lib.rs103
-rw-r--r--crates/ra_editor/src/line_index.rs119
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs150
-rw-r--r--crates/ra_editor/src/scope/mod.rs3
-rw-r--r--crates/ra_editor/src/scope/mod_scope.rs47
-rw-r--r--crates/ra_editor/src/symbols.rs34
-rw-r--r--crates/ra_editor/src/test_utils.rs12
-rw-r--r--crates/ra_editor/src/typing.rs205
-rw-r--r--crates/ra_lsp_server/src/caps.rs16
-rw-r--r--crates/ra_lsp_server/src/conv.rs66
-rw-r--r--crates/ra_lsp_server/src/lib.rs21
-rw-r--r--crates/ra_lsp_server/src/main.rs6
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs206
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs161
-rw-r--r--crates/ra_lsp_server/src/main_loop/subscriptions.rs6
-rw-r--r--crates/ra_lsp_server/src/path_map.rs28
-rw-r--r--crates/ra_lsp_server/src/project_model.rs32
-rw-r--r--crates/ra_lsp_server/src/req.rs27
-rw-r--r--crates/ra_lsp_server/src/server_world.rs76
-rw-r--r--crates/ra_lsp_server/src/thread_watcher.rs19
-rw-r--r--crates/ra_lsp_server/src/vfs.rs12
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs23
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs78
-rw-r--r--crates/ra_syntax/src/algo/mod.rs54
-rw-r--r--crates/ra_syntax/src/algo/visit.rs63
-rw-r--r--crates/ra_syntax/src/algo/walk.rs6
-rw-r--r--crates/ra_syntax/src/ast/generated.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera2
-rw-r--r--crates/ra_syntax/src/ast/mod.rs24
-rw-r--r--crates/ra_syntax/src/grammar/expressions/atom.rs58
-rw-r--r--crates/ra_syntax/src/grammar/expressions/mod.rs53
-rw-r--r--crates/ra_syntax/src/grammar/items/mod.rs45
-rw-r--r--crates/ra_syntax/src/grammar/items/traits.rs1
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs31
-rw-r--r--crates/ra_syntax/src/grammar/params.rs13
-rw-r--r--crates/ra_syntax/src/grammar/paths.rs2
-rw-r--r--crates/ra_syntax/src/grammar/patterns.rs22
-rw-r--r--crates/ra_syntax/src/grammar/type_params.rs11
-rw-r--r--crates/ra_syntax/src/grammar/types.rs18
-rw-r--r--crates/ra_syntax/src/lexer/mod.rs16
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs8
-rw-r--r--crates/ra_syntax/src/lexer/strings.rs4
-rw-r--r--crates/ra_syntax/src/lib.rs34
-rw-r--r--crates/ra_syntax/src/parser_api.rs8
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs54
-rw-r--r--crates/ra_syntax/src/parser_impl/mod.rs13
-rw-r--r--crates/ra_syntax/src/reparsing.rs247
-rw-r--r--crates/ra_syntax/src/syntax_kinds/mod.rs2
-rw-r--r--crates/ra_syntax/src/text_utils.rs2
-rw-r--r--crates/ra_syntax/src/utils.rs8
-rw-r--r--crates/ra_syntax/src/yellow/builder.rs12
-rw-r--r--crates/ra_syntax/src/yellow/mod.rs23
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs36
-rw-r--r--crates/ra_syntax/tests/test.rs9
-rw-r--r--crates/test_utils/src/lib.rs4
-rw-r--r--crates/tools/src/lib.rs12
-rw-r--r--crates/tools/src/main.rs45
-rw-r--r--crates/tools/tests/cli.rs16
76 files changed, 1930 insertions, 1524 deletions
diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs
index 645728a57..e45a6b5e2 100644
--- a/crates/gen_lsp_server/src/lib.rs
+++ b/crates/gen_lsp_server/src/lib.rs
@@ -59,7 +59,6 @@
59//! } 59//! }
60//! ``` 60//! ```
61 61
62
63#[macro_use] 62#[macro_use]
64extern crate failure; 63extern crate failure;
65#[macro_use] 64#[macro_use]
@@ -74,16 +73,16 @@ extern crate languageserver_types;
74mod msg; 73mod msg;
75mod stdio; 74mod stdio;
76 75
77use crossbeam_channel::{Sender, Receiver}; 76use crossbeam_channel::{Receiver, Sender};
78use languageserver_types::{ 77use languageserver_types::{
79 ServerCapabilities, InitializeResult, InitializeParams, 78 notification::{Exit, Initialized},
80 request::{Initialize, Shutdown}, 79 request::{Initialize, Shutdown},
81 notification::{Initialized, Exit}, 80 InitializeParams, InitializeResult, ServerCapabilities,
82}; 81};
83 82
84pub type Result<T> = ::std::result::Result<T, failure::Error>; 83pub type Result<T> = ::std::result::Result<T, failure::Error>;
85pub use { 84pub use {
86 msg::{RawMessage, RawRequest, RawResponse, RawResponseError, RawNotification, ErrorCode}, 85 msg::{ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, RawResponseError},
87 stdio::{stdio_transport, Threads}, 86 stdio::{stdio_transport, Threads},
88}; 87};
89 88
@@ -97,11 +96,7 @@ pub fn run_server(
97 caps: ServerCapabilities, 96 caps: ServerCapabilities,
98 receiver: Receiver<RawMessage>, 97 receiver: Receiver<RawMessage>,
99 sender: Sender<RawMessage>, 98 sender: Sender<RawMessage>,
100 server: impl FnOnce( 99 server: impl FnOnce(InitializeParams, &Receiver<RawMessage>, &Sender<RawMessage>) -> Result<()>,
101 InitializeParams,
102 &Receiver<RawMessage>,
103 &Sender<RawMessage>,
104 ) -> Result<()>,
105) -> Result<()> { 100) -> Result<()> {
106 info!("lsp server initializes"); 101 info!("lsp server initializes");
107 let params = initialize(&receiver, &sender, caps)?; 102 let params = initialize(&receiver, &sender, caps)?;
@@ -109,12 +104,10 @@ pub fn run_server(
109 server(params, &receiver, &sender)?; 104 server(params, &receiver, &sender)?;
110 info!("lsp server waiting for exit notification"); 105 info!("lsp server waiting for exit notification");
111 match receiver.recv() { 106 match receiver.recv() {
112 Some(RawMessage::Notification(n)) => { 107 Some(RawMessage::Notification(n)) => n
113 n.cast::<Exit>().map_err(|n| format_err!( 108 .cast::<Exit>()
114 "unexpected notification during shutdown: {:?}", n 109 .map_err(|n| format_err!("unexpected notification during shutdown: {:?}", n))?,
115 ))? 110 m => bail!("unexpected message during shutdown: {:?}", m),
116 }
117 m => bail!("unexpected message during shutdown: {:?}", m)
118 } 111 }
119 info!("lsp server shutdown complete"); 112 info!("lsp server shutdown complete");
120 Ok(()) 113 Ok(())
@@ -141,17 +134,15 @@ fn initialize(
141 Some(RawMessage::Request(req)) => match req.cast::<Initialize>() { 134 Some(RawMessage::Request(req)) => match req.cast::<Initialize>() {
142 Err(req) => bail!("expected initialize request, got {:?}", req), 135 Err(req) => bail!("expected initialize request, got {:?}", req),
143 Ok(req) => req, 136 Ok(req) => req,
144 } 137 },
145 msg => 138 msg => bail!("expected initialize request, got {:?}", msg),
146 bail!("expected initialize request, got {:?}", msg),
147 }; 139 };
148 let resp = RawResponse::ok::<Initialize>(id, &InitializeResult { capabilities: caps }); 140 let resp = RawResponse::ok::<Initialize>(id, &InitializeResult { capabilities: caps });
149 sender.send(RawMessage::Response(resp)); 141 sender.send(RawMessage::Response(resp));
150 match receiver.recv() { 142 match receiver.recv() {
151 Some(RawMessage::Notification(n)) => { 143 Some(RawMessage::Notification(n)) => {
152 n.cast::<Initialized>().map_err(|_| format_err!( 144 n.cast::<Initialized>()
153 "expected initialized notification" 145 .map_err(|_| format_err!("expected initialized notification"))?;
154 ))?;
155 } 146 }
156 _ => bail!("expected initialized notification"), 147 _ => bail!("expected initialized notification"),
157 } 148 }
diff --git a/crates/gen_lsp_server/src/msg.rs b/crates/gen_lsp_server/src/msg.rs
index 7fcac6f6d..e0d0aeab5 100644
--- a/crates/gen_lsp_server/src/msg.rs
+++ b/crates/gen_lsp_server/src/msg.rs
@@ -1,11 +1,8 @@
1use std::io::{BufRead, Write}; 1use std::io::{BufRead, Write};
2 2
3use serde_json::{Value, from_str, to_string, from_value, to_value}; 3use languageserver_types::{notification::Notification, request::Request};
4use serde::{Serialize, de::DeserializeOwned}; 4use serde::{de::DeserializeOwned, Serialize};
5use languageserver_types::{ 5use serde_json::{from_str, from_value, to_string, to_value, Value};
6 request::Request,
7 notification::Notification,
8};
9 6
10use Result; 7use Result;
11 8
@@ -81,7 +78,10 @@ impl RawMessage {
81 #[serde(flatten)] 78 #[serde(flatten)]
82 msg: RawMessage, 79 msg: RawMessage,
83 } 80 }
84 let text = to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?; 81 let text = to_string(&JsonRpc {
82 jsonrpc: "2.0",
83 msg: self,
84 })?;
85 write_msg_text(w, &text)?; 85 write_msg_text(w, &text)?;
86 Ok(()) 86 Ok(())
87 } 87 }
@@ -115,8 +115,9 @@ impl RawRequest {
115 115
116impl RawResponse { 116impl RawResponse {
117 pub fn ok<R>(id: u64, result: &R::Result) -> RawResponse 117 pub fn ok<R>(id: u64, result: &R::Result) -> RawResponse
118 where R: Request, 118 where
119 R::Result: Serialize, 119 R: Request,
120 R::Result: Serialize,
120 { 121 {
121 RawResponse { 122 RawResponse {
122 id, 123 id,
@@ -125,7 +126,11 @@ impl RawResponse {
125 } 126 }
126 } 127 }
127 pub fn err(id: u64, code: i32, message: String) -> RawResponse { 128 pub fn err(id: u64, code: i32, message: String) -> RawResponse {
128 let error = RawResponseError { code, message, data: None }; 129 let error = RawResponseError {
130 code,
131 message,
132 data: None,
133 };
129 RawResponse { 134 RawResponse {
130 id, 135 id,
131 result: None, 136 result: None,
@@ -174,7 +179,9 @@ fn read_msg_text(inp: &mut impl BufRead) -> Result<Option<String>> {
174 } 179 }
175 let mut parts = buf.splitn(2, ": "); 180 let mut parts = buf.splitn(2, ": ");
176 let header_name = parts.next().unwrap(); 181 let header_name = parts.next().unwrap();
177 let header_value = parts.next().ok_or_else(|| format_err!("malformed header: {:?}", buf))?; 182 let header_value = parts
183 .next()
184 .ok_or_else(|| format_err!("malformed header: {:?}", buf))?;
178 if header_name == "Content-Length" { 185 if header_name == "Content-Length" {
179 size = Some(header_value.parse::<usize>()?); 186 size = Some(header_value.parse::<usize>()?);
180 } 187 }
diff --git a/crates/gen_lsp_server/src/stdio.rs b/crates/gen_lsp_server/src/stdio.rs
index 81397bb2a..3d8a1712a 100644
--- a/crates/gen_lsp_server/src/stdio.rs
+++ b/crates/gen_lsp_server/src/stdio.rs
@@ -1,11 +1,9 @@
1use std::{ 1use std::{
2 io::{stdin, stdout},
2 thread, 3 thread,
3 io::{
4 stdout, stdin,
5 },
6}; 4};
7 5
8use crossbeam_channel::{Receiver, Sender, bounded}; 6use crossbeam_channel::{bounded, Receiver, Sender};
9 7
10use {RawMessage, Result}; 8use {RawMessage, Result};
11 9
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index c69577233..042dde1ac 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,17 +1,18 @@
1use std::{
2 fmt,
3 sync::Arc,
4 hash::{Hash, Hasher},
5};
6use salsa;
7use rustc_hash::FxHashSet;
8use ra_syntax::File;
9use ra_editor::{LineIndex};
10use crate::{ 1use crate::{
2 module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase},
11 symbol_index::SymbolIndex, 3 symbol_index::SymbolIndex,
12 module_map::{ModulesDatabase, ModuleTreeQuery, ModuleDescriptorQuery},
13 FileId, FileResolverImp, 4 FileId, FileResolverImp,
14}; 5};
6use ra_editor::LineIndex;
7use ra_syntax::File;
8use rustc_hash::FxHashSet;
9use salsa;
10
11use std::{
12 fmt,
13 hash::{Hash, Hasher},
14 sync::Arc,
15};
15 16
16#[derive(Default)] 17#[derive(Default)]
17pub(crate) struct RootDatabase { 18pub(crate) struct RootDatabase {
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs
index 8d9f38ca5..6f26f9935 100644
--- a/crates/ra_analysis/src/descriptors.rs
+++ b/crates/ra_analysis/src/descriptors.rs
@@ -1,41 +1,34 @@
1use std::{ 1use crate::{imp::FileResolverImp, FileId};
2 collections::BTreeMap,
3};
4use relative_path::RelativePathBuf;
5use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode, NameOwner},
4 text_utils::is_subrange,
6 SmolStr, 5 SmolStr,
7 ast::{self, NameOwner, AstNode},
8 text_utils::is_subrange
9};
10use crate::{
11 FileId,
12 imp::FileResolverImp,
13}; 6};
7use relative_path::RelativePathBuf;
8
9use std::collections::BTreeMap;
14 10
15#[derive(Debug, PartialEq, Eq, Hash)] 11#[derive(Debug, PartialEq, Eq, Hash)]
16pub struct ModuleDescriptor { 12pub struct ModuleDescriptor {
17 pub submodules: Vec<Submodule> 13 pub submodules: Vec<Submodule>,
18} 14}
19 15
20impl ModuleDescriptor { 16impl ModuleDescriptor {
21 pub fn new(root: ast::Root) -> ModuleDescriptor { 17 pub fn new(root: ast::Root) -> ModuleDescriptor {
22 let submodules = modules(root) 18 let submodules = modules(root).map(|(name, _)| Submodule { name }).collect();
23 .map(|(name, _)| Submodule { name })
24 .collect();
25 19
26 ModuleDescriptor { submodules } } 20 ModuleDescriptor { submodules }
21 }
27} 22}
28 23
29fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item=(SmolStr, ast::Module<'a>)> { 24fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> {
30 root 25 root.modules().filter_map(|module| {
31 .modules() 26 let name = module.name()?.text();
32 .filter_map(|module| { 27 if !module.has_semi() {
33 let name = module.name()?.text(); 28 return None;
34 if !module.has_semi() { 29 }
35 return None; 30 Some((name, module))
36 } 31 })
37 Some((name, module))
38 })
39} 32}
40 33
41#[derive(Clone, Hash, PartialEq, Eq, Debug)] 34#[derive(Clone, Hash, PartialEq, Eq, Debug)]
@@ -56,7 +49,7 @@ struct Node(usize);
56struct NodeData { 49struct NodeData {
57 file_id: FileId, 50 file_id: FileId,
58 links: Vec<Link>, 51 links: Vec<Link>,
59 parents: Vec<Link> 52 parents: Vec<Link>,
60} 53}
61 54
62#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 55#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -69,7 +62,6 @@ struct LinkData {
69 problem: Option<Problem>, 62 problem: Option<Problem>,
70} 63}
71 64
72
73#[derive(Clone, Debug, Hash, PartialEq, Eq)] 65#[derive(Clone, Debug, Hash, PartialEq, Eq)]
74pub enum Problem { 66pub enum Problem {
75 UnresolvedModule { 67 UnresolvedModule {
@@ -78,16 +70,18 @@ pub enum Problem {
78 NotDirOwner { 70 NotDirOwner {
79 move_to: RelativePathBuf, 71 move_to: RelativePathBuf,
80 candidate: RelativePathBuf, 72 candidate: RelativePathBuf,
81 } 73 },
82} 74}
83 75
84impl ModuleTreeDescriptor { 76impl ModuleTreeDescriptor {
85 pub(crate) fn new<'a>( 77 pub(crate) fn new<'a>(
86 files: impl Iterator<Item=(FileId, &'a ModuleDescriptor)> + Clone, 78 files: impl Iterator<Item = (FileId, &'a ModuleDescriptor)> + Clone,
87 file_resolver: &FileResolverImp, 79 file_resolver: &FileResolverImp,
88 ) -> ModuleTreeDescriptor { 80 ) -> ModuleTreeDescriptor {
89 let mut file_id2node = BTreeMap::new(); 81 let mut file_id2node = BTreeMap::new();
90 let mut nodes: Vec<NodeData> = files.clone().enumerate() 82 let mut nodes: Vec<NodeData> = files
83 .clone()
84 .enumerate()
91 .map(|(idx, (file_id, _))| { 85 .map(|(idx, (file_id, _))| {
92 file_id2node.insert(file_id, Node(idx)); 86 file_id2node.insert(file_id, Node(idx));
93 NodeData { 87 NodeData {
@@ -120,20 +114,19 @@ impl ModuleTreeDescriptor {
120 points_to, 114 points_to,
121 problem, 115 problem,
122 }) 116 })
123
124 } 117 }
125 } 118 }
126 119
127 ModuleTreeDescriptor { 120 ModuleTreeDescriptor {
128 nodes, links, file_id2node 121 nodes,
122 links,
123 file_id2node,
129 } 124 }
130 } 125 }
131 126
132 pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> { 127 pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> {
133 let node = self.file_id2node[&file_id]; 128 let node = self.file_id2node[&file_id];
134 self.node(node) 129 self.node(node).parents.clone()
135 .parents
136 .clone()
137 } 130 }
138 pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> { 131 pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> {
139 let node = self.file_id2node[&file_id]; 132 let node = self.file_id2node[&file_id];
@@ -141,10 +134,18 @@ impl ModuleTreeDescriptor {
141 .links 134 .links
142 .iter() 135 .iter()
143 .filter(|it| it.name(self) == name) 136 .filter(|it| it.name(self) == name)
144 .flat_map(|link| link.points_to(self).iter().map(|&node| self.node(node).file_id)) 137 .flat_map(|link| {
138 link.points_to(self)
139 .iter()
140 .map(|&node| self.node(node).file_id)
141 })
145 .collect() 142 .collect()
146 } 143 }
147 pub(crate) fn problems<'a, 'b>(&'b self, file_id: FileId, root: ast::Root<'a>) -> Vec<(ast::Name<'a>, &'b Problem)> { 144 pub(crate) fn problems<'a, 'b>(
145 &'b self,
146 file_id: FileId,
147 root: ast::Root<'a>,
148 ) -> Vec<(ast::Name<'a>, &'b Problem)> {
148 let node = self.file_id2node[&file_id]; 149 let node = self.file_id2node[&file_id];
149 self.node(node) 150 self.node(node)
150 .links 151 .links
@@ -176,7 +177,11 @@ impl Link {
176 fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] { 177 fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] {
177 &tree.link(self).points_to 178 &tree.link(self).points_to
178 } 179 }
179 pub(crate) fn bind_source<'a>(self, tree: &ModuleTreeDescriptor, root: ast::Root<'a>) -> ast::Module<'a> { 180 pub(crate) fn bind_source<'a>(
181 self,
182 tree: &ModuleTreeDescriptor,
183 root: ast::Root<'a>,
184 ) -> ast::Module<'a> {
180 modules(root) 185 modules(root)
181 .filter(|(name, _)| name == &tree.link(self).name) 186 .filter(|(name, _)| name == &tree.link(self).name)
182 .next() 187 .next()
@@ -185,22 +190,21 @@ impl Link {
185 } 190 }
186} 191}
187 192
188
189fn resolve_submodule( 193fn resolve_submodule(
190 file_id: FileId, 194 file_id: FileId,
191 name: &SmolStr, 195 name: &SmolStr,
192 file_resolver: &FileResolverImp 196 file_resolver: &FileResolverImp,
193) -> (Vec<FileId>, Option<Problem>) { 197) -> (Vec<FileId>, Option<Problem>) {
194 let mod_name = file_resolver.file_stem(file_id); 198 let mod_name = file_resolver.file_stem(file_id);
195 let is_dir_owner = 199 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
196 mod_name == "mod" || mod_name == "lib" || mod_name == "main";
197 200
198 let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); 201 let file_mod = RelativePathBuf::from(format!("../{}.rs", name));
199 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); 202 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name));
200 let points_to: Vec<FileId>; 203 let points_to: Vec<FileId>;
201 let problem: Option<Problem>; 204 let problem: Option<Problem>;
202 if is_dir_owner { 205 if is_dir_owner {
203 points_to = [&file_mod, &dir_mod].iter() 206 points_to = [&file_mod, &dir_mod]
207 .iter()
204 .filter_map(|path| file_resolver.resolve(file_id, path)) 208 .filter_map(|path| file_resolver.resolve(file_id, path))
205 .collect(); 209 .collect();
206 problem = if points_to.is_empty() { 210 problem = if points_to.is_empty() {
@@ -223,7 +227,7 @@ fn resolve_submodule(
223#[derive(Debug, Clone)] 227#[derive(Debug, Clone)]
224pub struct FnDescriptor { 228pub struct FnDescriptor {
225 pub name: String, 229 pub name: String,
226 pub label : String, 230 pub label: String,
227 pub ret_type: Option<String>, 231 pub ret_type: Option<String>,
228 pub params: Vec<String>, 232 pub params: Vec<String>,
229} 233}
@@ -233,9 +237,11 @@ impl FnDescriptor {
233 let name = node.name()?.text().to_string(); 237 let name = node.name()?.text().to_string();
234 238
235 // Strip the body out for the label. 239 // Strip the body out for the label.
236 let label : String = if let Some(body) = node.body() { 240 let label: String = if let Some(body) = node.body() {
237 let body_range = body.syntax().range(); 241 let body_range = body.syntax().range();
238 let label : String = node.syntax().children() 242 let label: String = node
243 .syntax()
244 .children()
239 .filter(|child| !is_subrange(body_range, child.range())) 245 .filter(|child| !is_subrange(body_range, child.range()))
240 .map(|node| node.text().to_string()) 246 .map(|node| node.text().to_string())
241 .collect(); 247 .collect();
@@ -251,7 +257,7 @@ impl FnDescriptor {
251 name, 257 name,
252 ret_type, 258 ret_type,
253 params, 259 params,
254 label 260 label,
255 }) 261 })
256 } 262 }
257 263
@@ -264,9 +270,11 @@ impl FnDescriptor {
264 270
265 // Maybe use param.pat here? See if we can just extract the name? 271 // Maybe use param.pat here? See if we can just extract the name?
266 //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); 272 //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
267 res.extend(param_list.params() 273 res.extend(
268 .filter_map(|p| p.pat()) 274 param_list
269 .map(|pat| pat.syntax().text().to_string()) 275 .params()
276 .filter_map(|p| p.pat())
277 .map(|pat| pat.syntax().text().to_string()),
270 ); 278 );
271 } 279 }
272 res 280 res
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5efcaeca0..f1403cb5d 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -1,32 +1,31 @@
1use std::{ 1use std::{
2 sync::{
3 Arc,
4 },
5 hash::{Hash, Hasher},
6 fmt,
7 collections::VecDeque, 2 collections::VecDeque,
3 fmt,
4 hash::{Hash, Hasher},
8 iter, 5 iter,
6 sync::Arc,
9}; 7};
10 8
11use relative_path::RelativePath; 9use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit};
12use rustc_hash::FxHashSet;
13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name};
14use ra_syntax::{ 10use ra_syntax::{
15 TextUnit, TextRange, SmolStr, File, AstNode, SyntaxNodeRef, 11 ast::{self, ArgListOwner, Expr, NameOwner},
12 AstNode, File, SmolStr,
16 SyntaxKind::*, 13 SyntaxKind::*,
17 ast::{self, NameOwner, ArgListOwner, Expr}, 14 SyntaxNodeRef, TextRange, TextUnit,
18}; 15};
16use relative_path::RelativePath;
17use rustc_hash::FxHashSet;
19 18
20use crate::{ 19use crate::{
21 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
22 JobToken, CrateGraph, CrateId,
23 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
24 descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, 20 descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem},
21 roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot},
22 CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, JobToken, Position,
23 Query, SourceChange, SourceFileEdit,
25}; 24};
26 25
27#[derive(Clone, Debug)] 26#[derive(Clone, Debug)]
28pub(crate) struct FileResolverImp { 27pub(crate) struct FileResolverImp {
29 inner: Arc<FileResolver> 28 inner: Arc<FileResolver>,
30} 29}
31 30
32impl PartialEq for FileResolverImp { 31impl PartialEq for FileResolverImp {
@@ -35,8 +34,7 @@ impl PartialEq for FileResolverImp {
35 } 34 }
36} 35}
37 36
38impl Eq for FileResolverImp { 37impl Eq for FileResolverImp {}
39}
40 38
41impl Hash for FileResolverImp { 39impl Hash for FileResolverImp {
42 fn hash<H: Hasher>(&self, hasher: &mut H) { 40 fn hash<H: Hasher>(&self, hasher: &mut H) {
@@ -67,17 +65,23 @@ impl Default for FileResolverImp {
67 fn file_stem(&self, _file_: FileId) -> String { 65 fn file_stem(&self, _file_: FileId) -> String {
68 panic!("file resolver not set") 66 panic!("file resolver not set")
69 } 67 }
70 fn resolve(&self, _file_id: FileId, _path: &::relative_path::RelativePath) -> Option<FileId> { 68 fn resolve(
69 &self,
70 _file_id: FileId,
71 _path: &::relative_path::RelativePath,
72 ) -> Option<FileId> {
71 panic!("file resolver not set") 73 panic!("file resolver not set")
72 } 74 }
73 } 75 }
74 FileResolverImp { inner: Arc::new(DummyResolver) } 76 FileResolverImp {
77 inner: Arc::new(DummyResolver),
78 }
75 } 79 }
76} 80}
77 81
78#[derive(Debug)] 82#[derive(Debug)]
79pub(crate) struct AnalysisHostImpl { 83pub(crate) struct AnalysisHostImpl {
80 data: WorldData 84 data: WorldData,
81} 85}
82 86
83impl AnalysisHostImpl { 87impl AnalysisHostImpl {
@@ -91,13 +95,13 @@ impl AnalysisHostImpl {
91 data: self.data.clone(), 95 data: self.data.clone(),
92 } 96 }
93 } 97 }
94 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { 98 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item = (FileId, Option<String>)>) {
95 self.data_mut() 99 self.data_mut().root.apply_changes(changes, None);
96 .root.apply_changes(changes, None);
97 } 100 }
98 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { 101 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) {
99 self.data_mut() 102 self.data_mut()
100 .root.apply_changes(&mut iter::empty(), Some(resolver)); 103 .root
104 .apply_changes(&mut iter::empty(), Some(resolver));
101 } 105 }
102 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 106 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
103 let mut visited = FxHashSet::default(); 107 let mut visited = FxHashSet::default();
@@ -131,7 +135,12 @@ impl AnalysisImpl {
131 if self.data.root.contains(file_id) { 135 if self.data.root.contains(file_id) {
132 return &self.data.root; 136 return &self.data.root;
133 } 137 }
134 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() 138 &**self
139 .data
140 .libs
141 .iter()
142 .find(|it| it.contains(file_id))
143 .unwrap()
135 } 144 }
136 pub fn file_syntax(&self, file_id: FileId) -> File { 145 pub fn file_syntax(&self, file_id: FileId) -> File {
137 self.root(file_id).syntax(file_id) 146 self.root(file_id).syntax(file_id)
@@ -142,18 +151,17 @@ impl AnalysisImpl {
142 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 151 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
143 let mut buf = Vec::new(); 152 let mut buf = Vec::new();
144 if query.libs { 153 if query.libs {
145 self.data.libs.iter() 154 self.data.libs.iter().for_each(|it| it.symbols(&mut buf));
146 .for_each(|it| it.symbols(&mut buf));
147 } else { 155 } else {
148 self.data.root.symbols(&mut buf); 156 self.data.root.symbols(&mut buf);
149 } 157 }
150 query.search(&buf, token) 158 query.search(&buf, token)
151
152 } 159 }
153 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 160 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
154 let root = self.root(file_id); 161 let root = self.root(file_id);
155 let module_tree = root.module_tree(); 162 let module_tree = root.module_tree();
156 module_tree.parent_modules(file_id) 163 module_tree
164 .parent_modules(file_id)
157 .iter() 165 .iter()
158 .map(|link| { 166 .map(|link| {
159 let file_id = link.owner(&module_tree); 167 let file_id = link.owner(&module_tree);
@@ -203,15 +211,17 @@ impl AnalysisImpl {
203 let file = root.syntax(file_id); 211 let file = root.syntax(file_id);
204 let syntax = file.syntax(); 212 let syntax = file.syntax();
205 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { 213 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
206
207 // First try to resolve the symbol locally 214 // First try to resolve the symbol locally
208 if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { 215 if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) {
209 let mut vec = vec![]; 216 let mut vec = vec![];
210 vec.push((file_id, FileSymbol { 217 vec.push((
211 name, 218 file_id,
212 node_range: range, 219 FileSymbol {
213 kind : NAME 220 name,
214 })); 221 node_range: range,
222 kind: NAME,
223 },
224 ));
215 225
216 return vec; 226 return vec;
217 } else { 227 } else {
@@ -224,17 +234,21 @@ impl AnalysisImpl {
224 if module.has_semi() { 234 if module.has_semi() {
225 let file_ids = self.resolve_module(&*module_tree, file_id, module); 235 let file_ids = self.resolve_module(&*module_tree, file_id, module);
226 236
227 let res = file_ids.into_iter().map(|id| { 237 let res = file_ids
228 let name = module.name() 238 .into_iter()
229 .map(|n| n.text()) 239 .map(|id| {
230 .unwrap_or_else(|| SmolStr::new("")); 240 let name = module
231 let symbol = FileSymbol { 241 .name()
232 name, 242 .map(|n| n.text())
233 node_range: TextRange::offset_len(0.into(), 0.into()), 243 .unwrap_or_else(|| SmolStr::new(""));
234 kind: MODULE, 244 let symbol = FileSymbol {
235 }; 245 name,
236 (id, symbol) 246 node_range: TextRange::offset_len(0.into(), 0.into()),
237 }).collect(); 247 kind: MODULE,
248 };
249 (id, symbol)
250 })
251 .collect();
238 252
239 return res; 253 return res;
240 } 254 }
@@ -245,12 +259,16 @@ impl AnalysisImpl {
245 259
246 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 260 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
247 let root = self.root(file_id); 261 let root = self.root(file_id);
248 let module_tree = root.module_tree(); 262 let module_tree = root.module_tree();
249 let syntax = root.syntax(file_id); 263 let syntax = root.syntax(file_id);
250 264
251 let mut res = ra_editor::diagnostics(&syntax) 265 let mut res = ra_editor::diagnostics(&syntax)
252 .into_iter() 266 .into_iter()
253 .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) 267 .map(|d| Diagnostic {
268 range: d.range,
269 message: d.msg,
270 fix: None,
271 })
254 .collect::<Vec<_>>(); 272 .collect::<Vec<_>>();
255 273
256 for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) { 274 for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) {
@@ -273,8 +291,14 @@ impl AnalysisImpl {
273 } 291 }
274 } 292 }
275 Problem::NotDirOwner { move_to, candidate } => { 293 Problem::NotDirOwner { move_to, candidate } => {
276 let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() }; 294 let move_file = FileSystemEdit::MoveFile {
277 let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) }; 295 file: file_id,
296 path: move_to.clone(),
297 };
298 let create_file = FileSystemEdit::CreateFile {
299 anchor: file_id,
300 path: move_to.join(candidate),
301 };
278 let fix = SourceChange { 302 let fix = SourceChange {
279 label: "move file and create module".to_string(), 303 label: "move file and create module".to_string(),
280 source_file_edits: Vec::new(), 304 source_file_edits: Vec::new(),
@@ -297,23 +321,34 @@ impl AnalysisImpl {
297 let file = self.file_syntax(file_id); 321 let file = self.file_syntax(file_id);
298 let offset = range.start(); 322 let offset = range.start();
299 let actions = vec![ 323 let actions = vec![
300 ("flip comma", ra_editor::flip_comma(&file, offset).map(|f| f())), 324 (
301 ("add `#[derive]`", ra_editor::add_derive(&file, offset).map(|f| f())), 325 "flip comma",
326 ra_editor::flip_comma(&file, offset).map(|f| f()),
327 ),
328 (
329 "add `#[derive]`",
330 ra_editor::add_derive(&file, offset).map(|f| f()),
331 ),
302 ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())), 332 ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())),
303 ("introduce variable", ra_editor::introduce_variable(&file, range).map(|f| f())), 333 (
334 "introduce variable",
335 ra_editor::introduce_variable(&file, range).map(|f| f()),
336 ),
304 ]; 337 ];
305 actions.into_iter() 338 actions
339 .into_iter()
306 .filter_map(|(name, local_edit)| { 340 .filter_map(|(name, local_edit)| {
307 Some(SourceChange::from_local_edit( 341 Some(SourceChange::from_local_edit(file_id, name, local_edit?))
308 file_id, name, local_edit?,
309 ))
310 }) 342 })
311 .collect() 343 .collect()
312 } 344 }
313 345
314 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken) 346 pub fn resolve_callable(
315 -> Option<(FnDescriptor, Option<usize>)> { 347 &self,
316 348 file_id: FileId,
349 offset: TextUnit,
350 token: &JobToken,
351 ) -> Option<(FnDescriptor, Option<usize>)> {
317 let root = self.root(file_id); 352 let root = self.root(file_id);
318 let file = root.syntax(file_id); 353 let file = root.syntax(file_id);
319 let syntax = file.syntax(); 354 let syntax = file.syntax();
@@ -332,9 +367,7 @@ impl AnalysisImpl {
332 let mut current_parameter = None; 367 let mut current_parameter = None;
333 368
334 let num_params = descriptor.params.len(); 369 let num_params = descriptor.params.len();
335 let has_self = fn_def.param_list() 370 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
336 .and_then(|l| l.self_param())
337 .is_some();
338 371
339 if num_params == 1 { 372 if num_params == 1 {
340 if !has_self { 373 if !has_self {
@@ -350,8 +383,11 @@ impl AnalysisImpl {
350 let start = arg_list.syntax().range().start(); 383 let start = arg_list.syntax().range().start();
351 384
352 let range_search = TextRange::from_to(start, offset); 385 let range_search = TextRange::from_to(start, offset);
353 let mut commas: usize = arg_list.syntax().text() 386 let mut commas: usize = arg_list
354 .slice(range_search).to_string() 387 .syntax()
388 .text()
389 .slice(range_search)
390 .to_string()
355 .matches(",") 391 .matches(",")
356 .count(); 392 .count();
357 393
@@ -381,7 +417,12 @@ impl AnalysisImpl {
381 self.world_symbols(query, token) 417 self.world_symbols(query, token)
382 } 418 }
383 419
384 fn resolve_module(&self, module_tree: &ModuleTreeDescriptor, file_id: FileId, module: ast::Module) -> Vec<FileId> { 420 fn resolve_module(
421 &self,
422 module_tree: &ModuleTreeDescriptor,
423 file_id: FileId,
424 module: ast::Module,
425 ) -> Vec<FileId> {
385 let name = match module.name() { 426 let name = match module.name() {
386 Some(name) => name.text(), 427 Some(name) => name.text(),
387 None => return Vec::new(), 428 None => return Vec::new(),
@@ -407,15 +448,17 @@ impl SourceChange {
407 label: label.to_string(), 448 label: label.to_string(),
408 source_file_edits: vec![file_edit], 449 source_file_edits: vec![file_edit],
409 file_system_edits: vec![], 450 file_system_edits: vec![],
410 cursor_position: edit.cursor_position 451 cursor_position: edit
411 .map(|offset| Position { offset, file_id }) 452 .cursor_position
453 .map(|offset| Position { offset, file_id }),
412 } 454 }
413 } 455 }
414} 456}
415 457
416impl CrateGraph { 458impl CrateGraph {
417 fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 459 fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
418 let (&crate_id, _) = self.crate_roots 460 let (&crate_id, _) = self
461 .crate_roots
419 .iter() 462 .iter()
420 .find(|(_crate_id, &root_id)| root_id == file_id)?; 463 .find(|(_crate_id, &root_id)| root_id == file_id)?;
421 Some(crate_id) 464 Some(crate_id)
@@ -424,7 +467,7 @@ impl CrateGraph {
424 467
425enum FnCallNode<'a> { 468enum FnCallNode<'a> {
426 CallExpr(ast::CallExpr<'a>), 469 CallExpr(ast::CallExpr<'a>),
427 MethodCallExpr(ast::MethodCallExpr<'a>) 470 MethodCallExpr(ast::MethodCallExpr<'a>),
428} 471}
429 472
430impl<'a> FnCallNode<'a> { 473impl<'a> FnCallNode<'a> {
@@ -440,27 +483,23 @@ impl<'a> FnCallNode<'a> {
440 483
441 pub fn name_ref(&self) -> Option<ast::NameRef> { 484 pub fn name_ref(&self) -> Option<ast::NameRef> {
442 match *self { 485 match *self {
443 FnCallNode::CallExpr(call_expr) => { 486 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
444 Some(match call_expr.expr()? { 487 Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
445 Expr::PathExpr(path_expr) => { 488 _ => return None,
446 path_expr.path()?.segment()?.name_ref()? 489 }),
447 }, 490
448 _ => return None 491 FnCallNode::MethodCallExpr(call_expr) => call_expr
449 }) 492 .syntax()
450 }, 493 .children()
451 494 .filter_map(ast::NameRef::cast)
452 FnCallNode::MethodCallExpr(call_expr) => { 495 .nth(0),
453 call_expr.syntax().children()
454 .filter_map(ast::NameRef::cast)
455 .nth(0)
456 }
457 } 496 }
458 } 497 }
459 498
460 pub fn arg_list(&self) -> Option<ast::ArgList> { 499 pub fn arg_list(&self) -> Option<ast::ArgList> {
461 match *self { 500 match *self {
462 FnCallNode::CallExpr(expr) => expr.arg_list(), 501 FnCallNode::CallExpr(expr) => expr.arg_list(),
463 FnCallNode::MethodCallExpr(expr) => expr.arg_list() 502 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
464 } 503 }
465 } 504 }
466} 505}
diff --git a/crates/ra_analysis/src/job.rs b/crates/ra_analysis/src/job.rs
index ea1652a26..2871f9839 100644
--- a/crates/ra_analysis/src/job.rs
+++ b/crates/ra_analysis/src/job.rs
@@ -14,15 +14,20 @@ impl JobHandle {
14 pub fn new() -> (JobHandle, JobToken) { 14 pub fn new() -> (JobHandle, JobToken) {
15 let (sender_alive, receiver_alive) = bounded(0); 15 let (sender_alive, receiver_alive) = bounded(0);
16 let (sender_canceled, receiver_canceled) = bounded(0); 16 let (sender_canceled, receiver_canceled) = bounded(0);
17 let token = JobToken { _job_alive: sender_alive, job_canceled: receiver_canceled }; 17 let token = JobToken {
18 let handle = JobHandle { job_alive: receiver_alive, _job_canceled: sender_canceled }; 18 _job_alive: sender_alive,
19 job_canceled: receiver_canceled,
20 };
21 let handle = JobHandle {
22 job_alive: receiver_alive,
23 _job_canceled: sender_canceled,
24 };
19 (handle, token) 25 (handle, token)
20 } 26 }
21 pub fn has_completed(&self) -> bool { 27 pub fn has_completed(&self) -> bool {
22 is_closed(&self.job_alive) 28 is_closed(&self.job_alive)
23 } 29 }
24 pub fn cancel(self) { 30 pub fn cancel(self) {}
25 }
26} 31}
27 32
28impl JobToken { 33impl JobToken {
@@ -31,7 +36,6 @@ impl JobToken {
31 } 36 }
32} 37}
33 38
34
35// We don't actually send messages through the channels, 39// We don't actually send messages through the channels,
36// and instead just check if the channel is closed, 40// and instead just check if the channel is closed,
37// so we use uninhabited enum as a message type 41// so we use uninhabited enum as a message type
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index d8b355a81..2eeacaabe 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -1,44 +1,40 @@
1extern crate parking_lot; 1extern crate parking_lot;
2#[macro_use] 2#[macro_use]
3extern crate log; 3extern crate log;
4extern crate fst;
4extern crate once_cell; 5extern crate once_cell;
5extern crate ra_syntax;
6extern crate ra_editor; 6extern crate ra_editor;
7extern crate fst; 7extern crate ra_syntax;
8extern crate rayon; 8extern crate rayon;
9extern crate relative_path; 9extern crate relative_path;
10#[macro_use] 10#[macro_use]
11extern crate crossbeam_channel; 11extern crate crossbeam_channel;
12extern crate im; 12extern crate im;
13extern crate salsa;
14extern crate rustc_hash; 13extern crate rustc_hash;
14extern crate salsa;
15 15
16mod symbol_index; 16mod db;
17mod module_map; 17mod descriptors;
18mod imp; 18mod imp;
19mod job; 19mod job;
20mod module_map;
20mod roots; 21mod roots;
21mod db; 22mod symbol_index;
22mod descriptors;
23 23
24use std::{ 24use std::{fmt::Debug, sync::Arc};
25 sync::Arc,
26 fmt::Debug,
27};
28 25
26use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
27use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
29use relative_path::{RelativePath, RelativePathBuf}; 28use relative_path::{RelativePath, RelativePathBuf};
30use ra_syntax::{File, TextRange, TextUnit, AtomEdit};
31use rustc_hash::FxHashMap; 29use rustc_hash::FxHashMap;
32use crate::imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
33 30
34pub use ra_editor::{
35 StructureNode, LineIndex, FileSymbol,
36 Runnable, RunnableKind, HighlightedRange, CompletionItem,
37 Fold, FoldKind
38};
39pub use crate::{ 31pub use crate::{
40 job::{JobToken, JobHandle},
41 descriptors::FnDescriptor, 32 descriptors::FnDescriptor,
33 job::{JobHandle, JobToken},
34};
35pub use ra_editor::{
36 CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable,
37 RunnableKind, StructureNode,
42}; 38};
43 39
44#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -59,20 +55,24 @@ pub trait FileResolver: Debug + Send + Sync + 'static {
59 55
60#[derive(Debug)] 56#[derive(Debug)]
61pub struct AnalysisHost { 57pub struct AnalysisHost {
62 imp: AnalysisHostImpl 58 imp: AnalysisHostImpl,
63} 59}
64 60
65impl AnalysisHost { 61impl AnalysisHost {
66 pub fn new() -> AnalysisHost { 62 pub fn new() -> AnalysisHost {
67 AnalysisHost { imp: AnalysisHostImpl::new() } 63 AnalysisHost {
64 imp: AnalysisHostImpl::new(),
65 }
68 } 66 }
69 pub fn analysis(&self) -> Analysis { 67 pub fn analysis(&self) -> Analysis {
70 Analysis { imp: self.imp.analysis() } 68 Analysis {
69 imp: self.imp.analysis(),
70 }
71 } 71 }
72 pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { 72 pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
73 self.change_files(::std::iter::once((file_id, text))); 73 self.change_files(::std::iter::once((file_id, text)));
74 } 74 }
75 pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { 75 pub fn change_files(&mut self, mut changes: impl Iterator<Item = (FileId, Option<String>)>) {
76 self.imp.change_files(&mut changes) 76 self.imp.change_files(&mut changes)
77 } 77 }
78 pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) { 78 pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) {
@@ -115,7 +115,7 @@ pub enum FileSystemEdit {
115 MoveFile { 115 MoveFile {
116 file: FileId, 116 file: FileId,
117 path: RelativePathBuf, 117 path: RelativePathBuf,
118 } 118 },
119} 119}
120 120
121#[derive(Debug)] 121#[derive(Debug)]
@@ -144,7 +144,7 @@ impl Query {
144 only_types: false, 144 only_types: false,
145 libs: false, 145 libs: false,
146 exact: false, 146 exact: false,
147 limit: usize::max_value() 147 limit: usize::max_value(),
148 } 148 }
149 } 149 }
150 pub fn only_types(&mut self) { 150 pub fn only_types(&mut self) {
@@ -163,7 +163,7 @@ impl Query {
163 163
164#[derive(Debug)] 164#[derive(Debug)]
165pub struct Analysis { 165pub struct Analysis {
166 imp: AnalysisImpl 166 imp: AnalysisImpl,
167} 167}
168 168
169impl Analysis { 169impl Analysis {
@@ -195,7 +195,11 @@ impl Analysis {
195 } 195 }
196 pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { 196 pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> {
197 let file = self.imp.file_syntax(file_id); 197 let file = self.imp.file_syntax(file_id);
198 Some(SourceChange::from_local_edit(file_id, "add semicolon", ra_editor::on_eq_typed(&file, offset)?)) 198 Some(SourceChange::from_local_edit(
199 file_id,
200 "add semicolon",
201 ra_editor::on_eq_typed(&file, offset)?,
202 ))
199 } 203 }
200 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { 204 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
201 let file = self.imp.file_syntax(file_id); 205 let file = self.imp.file_syntax(file_id);
@@ -204,8 +208,14 @@ impl Analysis {
204 pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 208 pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
205 self.imp.world_symbols(query, token) 209 self.imp.world_symbols(query, token)
206 } 210 }
207 pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 211 pub fn approximately_resolve_symbol(
208 self.imp.approximately_resolve_symbol(file_id, offset, token) 212 &self,
213 file_id: FileId,
214 offset: TextUnit,
215 token: &JobToken,
216 ) -> Vec<(FileId, FileSymbol)> {
217 self.imp
218 .approximately_resolve_symbol(file_id, offset, token)
209 } 219 }
210 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 220 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
211 self.imp.parent_module(file_id) 221 self.imp.parent_module(file_id)
@@ -239,15 +249,19 @@ impl Analysis {
239 ra_editor::folding_ranges(&file) 249 ra_editor::folding_ranges(&file)
240 } 250 }
241 251
242 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken) 252 pub fn resolve_callable(
243 -> Option<(FnDescriptor, Option<usize>)> { 253 &self,
254 file_id: FileId,
255 offset: TextUnit,
256 token: &JobToken,
257 ) -> Option<(FnDescriptor, Option<usize>)> {
244 self.imp.resolve_callable(file_id, offset, token) 258 self.imp.resolve_callable(file_id, offset, token)
245 } 259 }
246} 260}
247 261
248#[derive(Debug)] 262#[derive(Debug)]
249pub struct LibraryData { 263pub struct LibraryData {
250 root: roots::ReadonlySourceRoot 264 root: roots::ReadonlySourceRoot,
251} 265}
252 266
253impl LibraryData { 267impl LibraryData {
diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs
index c1799e3d4..ff0ec3cc7 100644
--- a/crates/ra_analysis/src/module_map.rs
+++ b/crates/ra_analysis/src/module_map.rs
@@ -1,10 +1,11 @@
1use std::sync::Arc;
2use crate::{ 1use crate::{
3 FileId, 2 db::SyntaxDatabase,
4 db::{SyntaxDatabase},
5 descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, 3 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
4 FileId,
6}; 5};
7 6
7use std::sync::Arc;
8
8salsa::query_group! { 9salsa::query_group! {
9 pub(crate) trait ModulesDatabase: SyntaxDatabase { 10 pub(crate) trait ModulesDatabase: SyntaxDatabase {
10 fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> { 11 fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> {
@@ -16,7 +17,6 @@ salsa::query_group! {
16 } 17 }
17} 18}
18 19
19
20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { 20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> {
21 let file = db.file_syntax(file_id); 21 let file = db.file_syntax(file_id);
22 Arc::new(ModuleDescriptor::new(file.ast())) 22 Arc::new(ModuleDescriptor::new(file.ast()))
@@ -29,6 +29,9 @@ fn module_tree(db: &impl ModulesDatabase, (): ()) -> Arc<ModuleTreeDescriptor> {
29 let module_descr = db.module_descriptor(file_id); 29 let module_descr = db.module_descriptor(file_id);
30 files.push((file_id, module_descr)); 30 files.push((file_id, module_descr));
31 } 31 }
32 let res = ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.resolver); 32 let res = ModuleTreeDescriptor::new(
33 files.iter().map(|(file_id, descr)| (*file_id, &**descr)),
34 &file_set.resolver,
35 );
33 Arc::new(res) 36 Arc::new(res)
34} 37}
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs
index 76bcecd38..1f2b21b27 100644
--- a/crates/ra_analysis/src/roots.rs
+++ b/crates/ra_analysis/src/roots.rs
@@ -1,22 +1,19 @@
1use std::{ 1use std::{panic, sync::Arc};
2 sync::Arc,
3 panic,
4};
5 2
6use once_cell::sync::OnceCell; 3use once_cell::sync::OnceCell;
7use rayon::prelude::*;
8use salsa::Database;
9use rustc_hash::{FxHashMap, FxHashSet};
10use ra_editor::LineIndex; 4use ra_editor::LineIndex;
11use ra_syntax::File; 5use ra_syntax::File;
6use rayon::prelude::*;
7use rustc_hash::{FxHashMap, FxHashSet};
8use salsa::Database;
12 9
13use crate::{ 10use crate::{
14 FileId,
15 imp::FileResolverImp,
16 symbol_index::SymbolIndex,
17 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
18 db::{self, FilesDatabase, SyntaxDatabase}, 11 db::{self, FilesDatabase, SyntaxDatabase},
12 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
13 imp::FileResolverImp,
19 module_map::ModulesDatabase, 14 module_map::ModulesDatabase,
15 symbol_index::SymbolIndex,
16 FileId,
20}; 17};
21 18
22pub(crate) trait SourceRoot { 19pub(crate) trait SourceRoot {
@@ -35,7 +32,7 @@ pub(crate) struct WritableSourceRoot {
35impl WritableSourceRoot { 32impl WritableSourceRoot {
36 pub fn apply_changes( 33 pub fn apply_changes(
37 &mut self, 34 &mut self,
38 changes: &mut dyn Iterator<Item=(FileId, Option<String>)>, 35 changes: &mut dyn Iterator<Item = (FileId, Option<String>)>,
39 file_resolver: Option<FileResolverImp>, 36 file_resolver: Option<FileResolverImp>,
40 ) { 37 ) {
41 let mut changed = FxHashSet::default(); 38 let mut changed = FxHashSet::default();
@@ -46,22 +43,22 @@ impl WritableSourceRoot {
46 removed.insert(file_id); 43 removed.insert(file_id);
47 } 44 }
48 Some(text) => { 45 Some(text) => {
49 self.db.query(db::FileTextQuery) 46 self.db
47 .query(db::FileTextQuery)
50 .set(file_id, Arc::new(text)); 48 .set(file_id, Arc::new(text));
51 changed.insert(file_id); 49 changed.insert(file_id);
52 } 50 }
53 } 51 }
54 } 52 }
55 let file_set = self.db.file_set(()); 53 let file_set = self.db.file_set(());
56 let mut files: FxHashSet<FileId> = file_set 54 let mut files: FxHashSet<FileId> = file_set.files.clone();
57 .files
58 .clone();
59 for file_id in removed { 55 for file_id in removed {
60 files.remove(&file_id); 56 files.remove(&file_id);
61 } 57 }
62 files.extend(changed); 58 files.extend(changed);
63 let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone()); 59 let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone());
64 self.db.query(db::FileSetQuery) 60 self.db
61 .query(db::FileSetQuery)
65 .set((), Arc::new(db::FileSet { files, resolver })); 62 .set((), Arc::new(db::FileSet { files, resolver }));
66 } 63 }
67} 64}
@@ -71,9 +68,7 @@ impl SourceRoot for WritableSourceRoot {
71 self.db.module_tree(()) 68 self.db.module_tree(())
72 } 69 }
73 fn contains(&self, file_id: FileId) -> bool { 70 fn contains(&self, file_id: FileId) -> bool {
74 self.db.file_set(()) 71 self.db.file_set(()).files.contains(&file_id)
75 .files
76 .contains(&file_id)
77 } 72 }
78 fn lines(&self, file_id: FileId) -> Arc<LineIndex> { 73 fn lines(&self, file_id: FileId) -> Arc<LineIndex> {
79 self.db.file_lines(file_id) 74 self.db.file_lines(file_id)
@@ -83,7 +78,7 @@ impl SourceRoot for WritableSourceRoot {
83 } 78 }
84 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { 79 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) {
85 let db = &self.db; 80 let db = &self.db;
86 let symbols = db.file_set(()); 81 let symbols = db.file_set(());
87 let symbols = symbols 82 let symbols = symbols
88 .files 83 .files
89 .iter() 84 .iter()
@@ -108,12 +103,15 @@ impl FileData {
108 } 103 }
109 } 104 }
110 fn lines(&self) -> &Arc<LineIndex> { 105 fn lines(&self) -> &Arc<LineIndex> {
111 self.lines.get_or_init(|| Arc::new(LineIndex::new(&self.text))) 106 self.lines
107 .get_or_init(|| Arc::new(LineIndex::new(&self.text)))
112 } 108 }
113 fn syntax(&self) -> &File { 109 fn syntax(&self) -> &File {
114 let text = &self.text; 110 let text = &self.text;
115 let syntax = &self.syntax; 111 let syntax = &self.syntax;
116 match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { 112 match panic::catch_unwind(panic::AssertUnwindSafe(|| {
113 syntax.get_or_init(|| File::parse(text))
114 })) {
117 Ok(file) => file, 115 Ok(file) => file,
118 Err(err) => { 116 Err(err) => {
119 error!("Parser paniced on:\n------\n{}\n------\n", text); 117 error!("Parser paniced on:\n------\n{}\n------\n", text);
@@ -131,22 +129,23 @@ pub(crate) struct ReadonlySourceRoot {
131} 129}
132 130
133impl ReadonlySourceRoot { 131impl ReadonlySourceRoot {
134 pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot { 132 pub(crate) fn new(
135 let modules = files.par_iter() 133 files: Vec<(FileId, String)>,
134 file_resolver: FileResolverImp,
135 ) -> ReadonlySourceRoot {
136 let modules = files
137 .par_iter()
136 .map(|(file_id, text)| { 138 .map(|(file_id, text)| {
137 let syntax = File::parse(text); 139 let syntax = File::parse(text);
138 let mod_descr = ModuleDescriptor::new(syntax.ast()); 140 let mod_descr = ModuleDescriptor::new(syntax.ast());
139 (*file_id, syntax, mod_descr) 141 (*file_id, syntax, mod_descr)
140 }) 142 })
141 .collect::<Vec<_>>(); 143 .collect::<Vec<_>>();
142 let module_tree = ModuleTreeDescriptor::new( 144 let module_tree =
143 modules.iter().map(|it| (it.0, &it.2)), 145 ModuleTreeDescriptor::new(modules.iter().map(|it| (it.0, &it.2)), &file_resolver);
144 &file_resolver,
145 );
146 146
147 let symbol_index = SymbolIndex::for_files( 147 let symbol_index =
148 modules.par_iter().map(|it| (it.0, it.1.clone())) 148 SymbolIndex::for_files(modules.par_iter().map(|it| (it.0, it.1.clone())));
149 );
150 let file_map: FxHashMap<FileId, FileData> = files 149 let file_map: FxHashMap<FileId, FileData> = files
151 .into_iter() 150 .into_iter()
152 .map(|(id, text)| (id, FileData::new(text))) 151 .map(|(id, text)| (id, FileData::new(text)))
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index 54672fde4..51eef8170 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -1,15 +1,16 @@
1use std::{ 1use crate::{FileId, JobToken, Query};
2 sync::Arc, 2use fst::{self, Streamer};
3 hash::{Hash, Hasher}, 3use ra_editor::{file_symbols, FileSymbol};
4};
5use ra_editor::{FileSymbol, file_symbols};
6use ra_syntax::{ 4use ra_syntax::{
7 File, 5 File,
8 SyntaxKind::{self, *}, 6 SyntaxKind::{self, *},
9}; 7};
10use fst::{self, Streamer};
11use rayon::prelude::*; 8use rayon::prelude::*;
12use crate::{Query, FileId, JobToken}; 9
10use std::{
11 hash::{Hash, Hasher},
12 sync::Arc,
13};
13 14
14#[derive(Debug)] 15#[derive(Debug)]
15pub(crate) struct SymbolIndex { 16pub(crate) struct SymbolIndex {
@@ -23,8 +24,7 @@ impl PartialEq for SymbolIndex {
23 } 24 }
24} 25}
25 26
26impl Eq for SymbolIndex { 27impl Eq for SymbolIndex {}
27}
28 28
29impl Hash for SymbolIndex { 29impl Hash for SymbolIndex {
30 fn hash<H: Hasher>(&self, hasher: &mut H) { 30 fn hash<H: Hasher>(&self, hasher: &mut H) {
@@ -33,14 +33,12 @@ impl Hash for SymbolIndex {
33} 33}
34 34
35impl SymbolIndex { 35impl SymbolIndex {
36 pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex { 36 pub(crate) fn for_files(files: impl ParallelIterator<Item = (FileId, File)>) -> SymbolIndex {
37 let mut symbols = files 37 let mut symbols = files
38 .flat_map(|(file_id, file)| { 38 .flat_map(|(file_id, file)| {
39 file_symbols(&file) 39 file_symbols(&file)
40 .into_iter() 40 .into_iter()
41 .map(move |symbol| { 41 .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol)))
42 (symbol.name.as_str().to_lowercase(), (file_id, symbol))
43 })
44 .collect::<Vec<_>>() 42 .collect::<Vec<_>>()
45 }) 43 })
46 .collect::<Vec<_>>(); 44 .collect::<Vec<_>>();
@@ -48,9 +46,7 @@ impl SymbolIndex {
48 symbols.dedup_by(|s1, s2| s1.0 == s2.0); 46 symbols.dedup_by(|s1, s2| s1.0 == s2.0);
49 let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = 47 let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) =
50 symbols.into_iter().unzip(); 48 symbols.into_iter().unzip();
51 let map = fst::Map::from_iter( 49 let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap();
52 names.into_iter().zip(0u64..)
53 ).unwrap();
54 SymbolIndex { symbols, map } 50 SymbolIndex { symbols, map }
55 } 51 }
56 52
@@ -65,7 +61,6 @@ impl Query {
65 indices: &[Arc<SymbolIndex>], 61 indices: &[Arc<SymbolIndex>],
66 token: &JobToken, 62 token: &JobToken,
67 ) -> Vec<(FileId, FileSymbol)> { 63 ) -> Vec<(FileId, FileSymbol)> {
68
69 let mut op = fst::map::OpBuilder::new(); 64 let mut op = fst::map::OpBuilder::new();
70 for file_symbols in indices.iter() { 65 for file_symbols in indices.iter() {
71 let automaton = fst::automaton::Subsequence::new(&self.lowercased); 66 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 2d3679fa9..e0c637d65 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -1,32 +1,31 @@
1extern crate relative_path;
2extern crate ra_analysis; 1extern crate ra_analysis;
3extern crate rustc_hash;
4extern crate ra_editor; 2extern crate ra_editor;
5extern crate ra_syntax; 3extern crate ra_syntax;
4extern crate relative_path;
5extern crate rustc_hash;
6extern crate test_utils; 6extern crate test_utils;
7 7
8use std::{ 8use std::sync::Arc;
9 sync::Arc,
10};
11 9
12use rustc_hash::FxHashMap; 10use ra_analysis::{
11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle,
12};
13use relative_path::{RelativePath, RelativePathBuf}; 13use relative_path::{RelativePath, RelativePathBuf};
14use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId, FnDescriptor}; 14use rustc_hash::FxHashMap;
15use test_utils::{assert_eq_dbg, extract_offset}; 15use test_utils::{assert_eq_dbg, extract_offset};
16 16
17#[derive(Debug)] 17#[derive(Debug)]
18struct FileMap(Vec<(FileId, RelativePathBuf)>); 18struct FileMap(Vec<(FileId, RelativePathBuf)>);
19 19
20impl FileMap { 20impl FileMap {
21 fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a { 21 fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a {
22 self.0.iter().map(|(id, path)| (*id, path.as_relative_path())) 22 self.0
23 .iter()
24 .map(|(id, path)| (*id, path.as_relative_path()))
23 } 25 }
24 26
25 fn path(&self, id: FileId) -> &RelativePath { 27 fn path(&self, id: FileId) -> &RelativePath {
26 self.iter() 28 self.iter().find(|&(it, _)| it == id).unwrap().1
27 .find(|&(it, _)| it == id)
28 .unwrap()
29 .1
30 } 29 }
31} 30}
32 31
@@ -71,10 +70,7 @@ fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
71 70
72#[test] 71#[test]
73fn test_resolve_module() { 72fn test_resolve_module() {
74 let snap = analysis(&[ 73 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
75 ("/lib.rs", "mod foo;"),
76 ("/foo.rs", "")
77 ]);
78 let (_handle, token) = JobHandle::new(); 74 let (_handle, token) = JobHandle::new();
79 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); 75 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
80 assert_eq_dbg( 76 assert_eq_dbg(
@@ -82,10 +78,7 @@ fn test_resolve_module() {
82 &symbols, 78 &symbols,
83 ); 79 );
84 80
85 let snap = analysis(&[ 81 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]);
86 ("/lib.rs", "mod foo;"),
87 ("/foo/mod.rs", "")
88 ]);
89 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); 82 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
90 assert_eq_dbg( 83 assert_eq_dbg(
91 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, 84 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
@@ -114,18 +107,12 @@ fn test_unresolved_module_diagnostic() {
114fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 107fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
115 let snap = analysis(&[("/lib.rs", "mod foo {}")]); 108 let snap = analysis(&[("/lib.rs", "mod foo {}")]);
116 let diagnostics = snap.diagnostics(FileId(1)); 109 let diagnostics = snap.diagnostics(FileId(1));
117 assert_eq_dbg( 110 assert_eq_dbg(r#"[]"#, &diagnostics);
118 r#"[]"#,
119 &diagnostics,
120 );
121} 111}
122 112
123#[test] 113#[test]
124fn test_resolve_parent_module() { 114fn test_resolve_parent_module() {
125 let snap = analysis(&[ 115 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
126 ("/lib.rs", "mod foo;"),
127 ("/foo.rs", ""),
128 ]);
129 let symbols = snap.parent_module(FileId(2)); 116 let symbols = snap.parent_module(FileId(2));
130 assert_eq_dbg( 117 assert_eq_dbg(
131 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, 118 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
@@ -135,10 +122,7 @@ fn test_resolve_parent_module() {
135 122
136#[test] 123#[test]
137fn test_resolve_crate_root() { 124fn test_resolve_crate_root() {
138 let mut host = analysis_host(&[ 125 let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
139 ("/lib.rs", "mod foo;"),
140 ("/foo.rs", ""),
141 ]);
142 let snap = host.analysis(); 126 let snap = host.analysis();
143 assert!(snap.crate_for(FileId(2)).is_empty()); 127 assert!(snap.crate_for(FileId(2)).is_empty());
144 128
@@ -152,20 +136,18 @@ fn test_resolve_crate_root() {
152 host.set_crate_graph(crate_graph); 136 host.set_crate_graph(crate_graph);
153 let snap = host.analysis(); 137 let snap = host.analysis();
154 138
155 assert_eq!( 139 assert_eq!(snap.crate_for(FileId(2)), vec![CrateId(1)],);
156 snap.crate_for(FileId(2)),
157 vec![CrateId(1)],
158 );
159} 140}
160 141
161#[test] 142#[test]
162fn test_fn_signature_two_args_first() { 143fn test_fn_signature_two_args_first() {
163 let (desc, param) = get_signature( 144 let (desc, param) = get_signature(
164r#"fn foo(x: u32, y: u32) -> u32 {x + y} 145 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
165fn bar() { foo(<|>3, ); }"#); 146fn bar() { foo(<|>3, ); }"#,
147 );
166 148
167 assert_eq!(desc.name, "foo".to_string()); 149 assert_eq!(desc.name, "foo".to_string());
168 assert_eq!(desc.params, vec!("x".to_string(),"y".to_string())); 150 assert_eq!(desc.params, vec!("x".to_string(), "y".to_string()));
169 assert_eq!(desc.ret_type, Some("-> u32".into())); 151 assert_eq!(desc.ret_type, Some("-> u32".into()));
170 assert_eq!(param, Some(0)); 152 assert_eq!(param, Some(0));
171} 153}
@@ -174,10 +156,11 @@ fn bar() { foo(<|>3, ); }"#);
174fn test_fn_signature_two_args_second() { 156fn test_fn_signature_two_args_second() {
175 let (desc, param) = get_signature( 157 let (desc, param) = get_signature(
176 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 158 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
177fn bar() { foo(3, <|>); }"#); 159fn bar() { foo(3, <|>); }"#,
160 );
178 161
179 assert_eq!(desc.name, "foo".to_string()); 162 assert_eq!(desc.name, "foo".to_string());
180 assert_eq!(desc.params, vec!("x".to_string(),"y".to_string())); 163 assert_eq!(desc.params, vec!("x".to_string(), "y".to_string()));
181 assert_eq!(desc.ret_type, Some("-> u32".into())); 164 assert_eq!(desc.ret_type, Some("-> u32".into()));
182 assert_eq!(param, Some(1)); 165 assert_eq!(param, Some(1));
183} 166}
@@ -185,8 +168,9 @@ fn bar() { foo(3, <|>); }"#);
185#[test] 168#[test]
186fn test_fn_signature_for_impl() { 169fn test_fn_signature_for_impl() {
187 let (desc, param) = get_signature( 170 let (desc, param) = get_signature(
188r#"struct F; impl F { pub fn new() { F{}} } 171 r#"struct F; impl F { pub fn new() { F{}} }
189fn bar() {let _ : F = F::new(<|>);}"#); 172fn bar() {let _ : F = F::new(<|>);}"#,
173 );
190 174
191 assert_eq!(desc.name, "new".to_string()); 175 assert_eq!(desc.name, "new".to_string());
192 assert_eq!(desc.params, Vec::<String>::new()); 176 assert_eq!(desc.params, Vec::<String>::new());
@@ -197,7 +181,7 @@ fn bar() {let _ : F = F::new(<|>);}"#);
197#[test] 181#[test]
198fn test_fn_signature_for_method_self() { 182fn test_fn_signature_for_method_self() {
199 let (desc, param) = get_signature( 183 let (desc, param) = get_signature(
200r#"struct F; 184 r#"struct F;
201impl F { 185impl F {
202 pub fn new() -> F{ 186 pub fn new() -> F{
203 F{} 187 F{}
@@ -209,7 +193,8 @@ impl F {
209fn bar() { 193fn bar() {
210 let f : F = F::new(); 194 let f : F = F::new();
211 f.do_it(<|>); 195 f.do_it(<|>);
212}"#); 196}"#,
197 );
213 198
214 assert_eq!(desc.name, "do_it".to_string()); 199 assert_eq!(desc.name, "do_it".to_string());
215 assert_eq!(desc.params, vec!["&self".to_string()]); 200 assert_eq!(desc.params, vec!["&self".to_string()]);
@@ -220,7 +205,7 @@ fn bar() {
220#[test] 205#[test]
221fn test_fn_signature_for_method_with_arg() { 206fn test_fn_signature_for_method_with_arg() {
222 let (desc, param) = get_signature( 207 let (desc, param) = get_signature(
223r#"struct F; 208 r#"struct F;
224impl F { 209impl F {
225 pub fn new() -> F{ 210 pub fn new() -> F{
226 F{} 211 F{}
@@ -232,7 +217,8 @@ impl F {
232fn bar() { 217fn bar() {
233 let f : F = F::new(); 218 let f : F = F::new();
234 f.do_it(<|>); 219 f.do_it(<|>);
235}"#); 220}"#,
221 );
236 222
237 assert_eq!(desc.name, "do_it".to_string()); 223 assert_eq!(desc.name, "do_it".to_string());
238 assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]); 224 assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]);
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 11605cfd8..239d846b3 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -2,19 +2,17 @@ extern crate clap;
2#[macro_use] 2#[macro_use]
3extern crate failure; 3extern crate failure;
4extern crate join_to_string; 4extern crate join_to_string;
5extern crate ra_syntax;
6extern crate ra_editor; 5extern crate ra_editor;
6extern crate ra_syntax;
7extern crate tools; 7extern crate tools;
8 8
9use std::{ 9use std::{fs, io::Read, path::Path, time::Instant};
10 fs, io::Read, path::Path, 10
11 time::Instant
12};
13use clap::{App, Arg, SubCommand}; 11use clap::{App, Arg, SubCommand};
14use join_to_string::join; 12use join_to_string::join;
13use ra_editor::{extend_selection, file_structure, syntax_tree};
14use ra_syntax::{File, TextRange};
15use tools::collect_tests; 15use tools::collect_tests;
16use ra_syntax::{TextRange, File};
17use ra_editor::{syntax_tree, file_structure, extend_selection};
18 16
19type Result<T> = ::std::result::Result<T, failure::Error>; 17type Result<T> = ::std::result::Result<T, failure::Error>;
20 18
@@ -36,14 +34,12 @@ fn main() -> Result<()> {
36 .takes_value(true), 34 .takes_value(true),
37 ), 35 ),
38 ) 36 )
39 .subcommand( 37 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump")))
40 SubCommand::with_name("parse")
41 .arg(Arg::with_name("no-dump").long("--no-dump"))
42 )
43 .subcommand(SubCommand::with_name("symbols")) 38 .subcommand(SubCommand::with_name("symbols"))
44 .subcommand(SubCommand::with_name("extend-selection") 39 .subcommand(
45 .arg(Arg::with_name("start")) 40 SubCommand::with_name("extend-selection")
46 .arg(Arg::with_name("end")) 41 .arg(Arg::with_name("start"))
42 .arg(Arg::with_name("end")),
47 ) 43 )
48 .get_matches(); 44 .get_matches();
49 match matches.subcommand() { 45 match matches.subcommand() {
@@ -116,7 +112,8 @@ fn selections(file: &File, start: u32, end: u32) -> String {
116 ranges.push(r); 112 ranges.push(r);
117 cur = extend_selection(&file, r); 113 cur = extend_selection(&file, r);
118 } 114 }
119 let ranges = ranges.iter() 115 let ranges = ranges
116 .iter()
120 .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end()))) 117 .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end())))
121 .map(|(s, e)| format!("({} {})", s, e)); 118 .map(|(s, e)| format!("({} {})", s, e));
122 join(ranges) 119 join(ranges)
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index 7b0a48c81..cadcd2720 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -1,17 +1,14 @@
1use join_to_string::join; 1use join_to_string::join;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 File, TextUnit, TextRange, Direction, 4 algo::{find_covering_node, find_leaf_at_offset},
5 ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner}, 5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
6 Direction, File,
6 SyntaxKind::{COMMA, WHITESPACE}, 7 SyntaxKind::{COMMA, WHITESPACE},
7 SyntaxNodeRef, 8 SyntaxNodeRef, TextRange, TextUnit,
8 algo::{
9 find_leaf_at_offset,
10 find_covering_node,
11 },
12}; 9};
13 10
14use crate::{EditBuilder, Edit, find_node_at_offset}; 11use crate::{find_node_at_offset, Edit, EditBuilder};
15 12
16#[derive(Debug)] 13#[derive(Debug)]
17pub struct LocalEdit { 14pub struct LocalEdit {
@@ -52,9 +49,7 @@ pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
52 edit.insert(node_start, "#[derive()]\n".to_string()); 49 edit.insert(node_start, "#[derive()]\n".to_string());
53 node_start + TextUnit::of_str("#[derive(") 50 node_start + TextUnit::of_str("#[derive(")
54 } 51 }
55 Some(tt) => { 52 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'),
56 tt.syntax().range().end() - TextUnit::of_char(')')
57 }
58 }; 53 };
59 LocalEdit { 54 LocalEdit {
60 edit: edit.finish(), 55 edit: edit.finish(),
@@ -74,14 +69,19 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() ->
74 let mut buf = String::new(); 69 let mut buf = String::new();
75 buf.push_str("\n\nimpl"); 70 buf.push_str("\n\nimpl");
76 if let Some(type_params) = type_params { 71 if let Some(type_params) = type_params {
77 type_params.syntax().text() 72 type_params.syntax().text().push_to(&mut buf);
78 .push_to(&mut buf);
79 } 73 }
80 buf.push_str(" "); 74 buf.push_str(" ");
81 buf.push_str(name.text().as_str()); 75 buf.push_str(name.text().as_str());
82 if let Some(type_params) = type_params { 76 if let Some(type_params) = type_params {
83 let lifetime_params = type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); 77 let lifetime_params = type_params
84 let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); 78 .lifetime_params()
79 .filter_map(|it| it.lifetime())
80 .map(|it| it.text());
81 let type_params = type_params
82 .type_params()
83 .filter_map(|it| it.name())
84 .map(|it| it.text());
85 join(lifetime_params.chain(type_params)) 85 join(lifetime_params.chain(type_params))
86 .surround_with("<", ">") 86 .surround_with("<", ">")
87 .to_buf(&mut buf); 87 .to_buf(&mut buf);
@@ -97,10 +97,17 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() ->
97 }) 97 })
98} 98}
99 99
100pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> { 100pub fn introduce_variable<'a>(
101 file: &'a File,
102 range: TextRange,
103) -> Option<impl FnOnce() -> LocalEdit + 'a> {
101 let node = find_covering_node(file.syntax(), range); 104 let node = find_covering_node(file.syntax(), range);
102 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; 105 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;
103 let anchor_stmt = expr.syntax().ancestors().filter_map(ast::Stmt::cast).next()?; 106 let anchor_stmt = expr
107 .syntax()
108 .ancestors()
109 .filter_map(ast::Stmt::cast)
110 .next()?;
104 let indent = anchor_stmt.syntax().prev_sibling()?; 111 let indent = anchor_stmt.syntax().prev_sibling()?;
105 if indent.kind() != WHITESPACE { 112 if indent.kind() != WHITESPACE {
106 return None; 113 return None;
@@ -191,7 +198,8 @@ mod tests {
191 " 198 "
192fn foo() { 199fn foo() {
193 foo(<|>1 + 1<|>); 200 foo(<|>1 + 1<|>);
194}", " 201}",
202 "
195fn foo() { 203fn foo() {
196 let <|>var_name = 1 + 1; 204 let <|>var_name = 1 + 1;
197 foo(var_name); 205 foo(var_name);
@@ -201,11 +209,12 @@ fn foo() {
201 } 209 }
202 #[test] 210 #[test]
203 fn test_intrdoduce_var_expr_stmt() { 211 fn test_intrdoduce_var_expr_stmt() {
204check_action_range( 212 check_action_range(
205 " 213 "
206fn foo() { 214fn foo() {
207 <|>1 + 1<|>; 215 <|>1 + 1<|>;
208}", " 216}",
217 "
209fn foo() { 218fn foo() {
210 let <|>var_name = 1 + 1; 219 let <|>var_name = 1 + 1;
211}", 220}",
diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs
index b6095dca9..86ef46ebd 100644
--- a/crates/ra_editor/src/completion.rs
+++ b/crates/ra_editor/src/completion.rs
@@ -1,17 +1,18 @@
1use rustc_hash::{FxHashMap, FxHashSet}; 1use rustc_hash::{FxHashMap, FxHashSet};
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, 4 algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx},
5 ast::{self, LoopBodyOwner, ModuleItemOwner}, 5 ast::{self, LoopBodyOwner, ModuleItemOwner},
6 algo::{
7 visit::{visitor, Visitor, visitor_ctx, VisitorCtx},
8 },
9 text_utils::is_subrange, 6 text_utils::is_subrange,
7 AstNode, File,
8 SyntaxKind::*,
9 SyntaxNodeRef, TextUnit,
10}; 10};
11 11
12use crate::{ 12use crate::{
13 AtomEdit, find_node_at_offset, 13 find_node_at_offset,
14 scope::{FnScopes, ModuleScope}, 14 scope::{FnScopes, ModuleScope},
15 AtomEdit,
15}; 16};
16 17
17#[derive(Debug)] 18#[derive(Debug)]
@@ -21,7 +22,7 @@ pub struct CompletionItem {
21 /// What string is used for filtering, defaults to label 22 /// What string is used for filtering, defaults to label
22 pub lookup: Option<String>, 23 pub lookup: Option<String>,
23 /// What is inserted, defaults to label 24 /// What is inserted, defaults to label
24 pub snippet: Option<String> 25 pub snippet: Option<String>,
25} 26}
26 27
27pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> { 28pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> {
@@ -40,7 +41,12 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI
40 param_completions(name_ref.syntax(), &mut res); 41 param_completions(name_ref.syntax(), &mut res);
41 } 42 }
42 let name_range = name_ref.syntax().range(); 43 let name_range = name_ref.syntax().range();
43 let top_node = name_ref.syntax().ancestors().take_while(|it| it.range() == name_range).last().unwrap(); 44 let top_node = name_ref
45 .syntax()
46 .ancestors()
47 .take_while(|it| it.range() == name_range)
48 .last()
49 .unwrap();
44 match top_node.parent().map(|it| it.kind()) { 50 match top_node.parent().map(|it| it.kind()) {
45 Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res), 51 Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res),
46 _ => (), 52 _ => (),
@@ -68,21 +74,23 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<Completi
68 if let Some(items) = visitor() 74 if let Some(items) = visitor()
69 .visit::<ast::Root, _>(|it| Some(it.items())) 75 .visit::<ast::Root, _>(|it| Some(it.items()))
70 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items())) 76 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items()))
71 .accept(node) { 77 .accept(node)
78 {
72 if let Some(items) = items { 79 if let Some(items) = items {
73 let scope = ModuleScope::new(items); 80 let scope = ModuleScope::new(items);
74 acc.extend( 81 acc.extend(
75 scope.entries().iter() 82 scope
83 .entries()
84 .iter()
76 .filter(|entry| entry.syntax() != name_ref.syntax()) 85 .filter(|entry| entry.syntax() != name_ref.syntax())
77 .map(|entry| CompletionItem { 86 .map(|entry| CompletionItem {
78 label: entry.name().to_string(), 87 label: entry.name().to_string(),
79 lookup: None, 88 lookup: None,
80 snippet: None, 89 snippet: None,
81 }) 90 }),
82 ); 91 );
83 } 92 }
84 break; 93 break;
85
86 } else if !visited_fn { 94 } else if !visited_fn {
87 if let Some(fn_def) = ast::FnDef::cast(node) { 95 if let Some(fn_def) = ast::FnDef::cast(node) {
88 visited_fn = true; 96 visited_fn = true;
@@ -103,26 +111,34 @@ fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
103 .visit::<ast::ItemList, _>(process) 111 .visit::<ast::ItemList, _>(process)
104 .accept(node); 112 .accept(node);
105 } 113 }
106 params.into_iter() 114 params
115 .into_iter()
107 .filter_map(|(label, (count, param))| { 116 .filter_map(|(label, (count, param))| {
108 let lookup = param.pat()?.syntax().text().to_string(); 117 let lookup = param.pat()?.syntax().text().to_string();
109 if count < 2 { None } else { Some((label, lookup)) } 118 if count < 2 {
119 None
120 } else {
121 Some((label, lookup))
122 }
110 }) 123 })
111 .for_each(|(label, lookup)| { 124 .for_each(|(label, lookup)| {
112 acc.push(CompletionItem { 125 acc.push(CompletionItem {
113 label, lookup: Some(lookup), snippet: None 126 label,
127 lookup: Some(lookup),
128 snippet: None,
114 }) 129 })
115 }); 130 });
116 131
117 fn process<'a, N: ast::FnDefOwner<'a>>(node: N, params: &mut FxHashMap<String, (u32, ast::Param<'a>)>) { 132 fn process<'a, N: ast::FnDefOwner<'a>>(
133 node: N,
134 params: &mut FxHashMap<String, (u32, ast::Param<'a>)>,
135 ) {
118 node.functions() 136 node.functions()
119 .filter_map(|it| it.param_list()) 137 .filter_map(|it| it.param_list())
120 .flat_map(|it| it.params()) 138 .flat_map(|it| it.params())
121 .for_each(|param| { 139 .for_each(|param| {
122 let text = param.syntax().text().to_string(); 140 let text = param.syntax().text().to_string();
123 params.entry(text) 141 params.entry(text).or_insert((0, param)).0 += 1;
124 .or_insert((0, param))
125 .0 += 1;
126 }) 142 })
127 } 143 }
128} 144}
@@ -134,8 +150,12 @@ fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool {
134 } 150 }
135} 151}
136 152
137 153fn complete_expr_keywords(
138fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) { 154 file: &File,
155 fn_def: ast::FnDef,
156 name_ref: ast::NameRef,
157 acc: &mut Vec<CompletionItem>,
158) {
139 acc.push(keyword("if", "if $0 {}")); 159 acc.push(keyword("if", "if $0 {}"));
140 acc.push(keyword("match", "match $0 {}")); 160 acc.push(keyword("match", "match $0 {}"));
141 acc.push(keyword("while", "while $0 {}")); 161 acc.push(keyword("while", "while $0 {}"));
@@ -186,9 +206,14 @@ fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<Complet
186 // return None; 206 // return None;
187 // } 207 // }
188 208
189 let is_stmt = match name_ref.syntax().ancestors().filter_map(ast::ExprStmt::cast).next() { 209 let is_stmt = match name_ref
210 .syntax()
211 .ancestors()
212 .filter_map(ast::ExprStmt::cast)
213 .next()
214 {
190 None => false, 215 None => false,
191 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range() 216 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
192 }; 217 };
193 let snip = match (is_stmt, fn_def.ret_type().is_some()) { 218 let snip = match (is_stmt, fn_def.ret_type().is_some()) {
194 (true, true) => "return $0;", 219 (true, true) => "return $0;",
@@ -209,39 +234,37 @@ fn keyword(kw: &str, snip: &str) -> CompletionItem {
209 234
210fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { 235fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) {
211 acc.push(CompletionItem { 236 acc.push(CompletionItem {
212 label: "pd".to_string(), 237 label: "pd".to_string(),
213 lookup: None, 238 lookup: None,
214 snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()), 239 snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()),
215 } 240 });
216 );
217 acc.push(CompletionItem { 241 acc.push(CompletionItem {
218 label: "ppd".to_string(), 242 label: "ppd".to_string(),
219 lookup: None, 243 lookup: None,
220 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()), 244 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()),
221 } 245 });
222 );
223} 246}
224 247
225fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { 248fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
226 acc.push(CompletionItem { 249 acc.push(CompletionItem {
227 label: "tfn".to_string(), 250 label: "tfn".to_string(),
228 lookup: None, 251 lookup: None,
229 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), 252 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()),
230 } 253 });
231 );
232} 254}
233 255
234fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { 256fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
235 let mut shadowed = FxHashSet::default(); 257 let mut shadowed = FxHashSet::default();
236 acc.extend( 258 acc.extend(
237 scopes.scope_chain(name_ref.syntax()) 259 scopes
260 .scope_chain(name_ref.syntax())
238 .flat_map(|scope| scopes.entries(scope).iter()) 261 .flat_map(|scope| scopes.entries(scope).iter())
239 .filter(|entry| shadowed.insert(entry.name())) 262 .filter(|entry| shadowed.insert(entry.name()))
240 .map(|entry| CompletionItem { 263 .map(|entry| CompletionItem {
241 label: entry.name().to_string(), 264 label: entry.name().to_string(),
242 lookup: None, 265 lookup: None,
243 snippet: None, 266 snippet: None,
244 }) 267 }),
245 ); 268 );
246 if scopes.self_param.is_some() { 269 if scopes.self_param.is_some() {
247 acc.push(CompletionItem { 270 acc.push(CompletionItem {
@@ -281,20 +304,24 @@ mod tests {
281 304
282 #[test] 305 #[test]
283 fn test_completion_let_scope() { 306 fn test_completion_let_scope() {
284 check_scope_completion(r" 307 check_scope_completion(
308 r"
285 fn quux(x: i32) { 309 fn quux(x: i32) {
286 let y = 92; 310 let y = 92;
287 1 + <|>; 311 1 + <|>;
288 let z = (); 312 let z = ();
289 } 313 }
290 ", r#"[CompletionItem { label: "y", lookup: None, snippet: None }, 314 ",
315 r#"[CompletionItem { label: "y", lookup: None, snippet: None },
291 CompletionItem { label: "x", lookup: None, snippet: None }, 316 CompletionItem { label: "x", lookup: None, snippet: None },
292 CompletionItem { label: "quux", lookup: None, snippet: None }]"#); 317 CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
318 );
293 } 319 }
294 320
295 #[test] 321 #[test]
296 fn test_completion_if_let_scope() { 322 fn test_completion_if_let_scope() {
297 check_scope_completion(r" 323 check_scope_completion(
324 r"
298 fn quux() { 325 fn quux() {
299 if let Some(x) = foo() { 326 if let Some(x) = foo() {
300 let y = 92; 327 let y = 92;
@@ -304,67 +331,85 @@ mod tests {
304 1 + <|> 331 1 + <|>
305 } 332 }
306 } 333 }
307 ", r#"[CompletionItem { label: "b", lookup: None, snippet: None }, 334 ",
335 r#"[CompletionItem { label: "b", lookup: None, snippet: None },
308 CompletionItem { label: "a", lookup: None, snippet: None }, 336 CompletionItem { label: "a", lookup: None, snippet: None },
309 CompletionItem { label: "quux", lookup: None, snippet: None }]"#); 337 CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
338 );
310 } 339 }
311 340
312 #[test] 341 #[test]
313 fn test_completion_for_scope() { 342 fn test_completion_for_scope() {
314 check_scope_completion(r" 343 check_scope_completion(
344 r"
315 fn quux() { 345 fn quux() {
316 for x in &[1, 2, 3] { 346 for x in &[1, 2, 3] {
317 <|> 347 <|>
318 } 348 }
319 } 349 }
320 ", r#"[CompletionItem { label: "x", lookup: None, snippet: None }, 350 ",
321 CompletionItem { label: "quux", lookup: None, snippet: None }]"#); 351 r#"[CompletionItem { label: "x", lookup: None, snippet: None },
352 CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
353 );
322 } 354 }
323 355
324 #[test] 356 #[test]
325 fn test_completion_mod_scope() { 357 fn test_completion_mod_scope() {
326 check_scope_completion(r" 358 check_scope_completion(
359 r"
327 struct Foo; 360 struct Foo;
328 enum Baz {} 361 enum Baz {}
329 fn quux() { 362 fn quux() {
330 <|> 363 <|>
331 } 364 }
332 ", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, 365 ",
366 r#"[CompletionItem { label: "Foo", lookup: None, snippet: None },
333 CompletionItem { label: "Baz", lookup: None, snippet: None }, 367 CompletionItem { label: "Baz", lookup: None, snippet: None },
334 CompletionItem { label: "quux", lookup: None, snippet: None }]"#); 368 CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
369 );
335 } 370 }
336 371
337 #[test] 372 #[test]
338 fn test_completion_mod_scope_no_self_use() { 373 fn test_completion_mod_scope_no_self_use() {
339 check_scope_completion(r" 374 check_scope_completion(
375 r"
340 use foo<|>; 376 use foo<|>;
341 ", r#"[]"#); 377 ",
378 r#"[]"#,
379 );
342 } 380 }
343 381
344 #[test] 382 #[test]
345 fn test_completion_mod_scope_nested() { 383 fn test_completion_mod_scope_nested() {
346 check_scope_completion(r" 384 check_scope_completion(
385 r"
347 struct Foo; 386 struct Foo;
348 mod m { 387 mod m {
349 struct Bar; 388 struct Bar;
350 fn quux() { <|> } 389 fn quux() { <|> }
351 } 390 }
352 ", r#"[CompletionItem { label: "Bar", lookup: None, snippet: None }, 391 ",
353 CompletionItem { label: "quux", lookup: None, snippet: None }]"#); 392 r#"[CompletionItem { label: "Bar", lookup: None, snippet: None },
393 CompletionItem { label: "quux", lookup: None, snippet: None }]"#,
394 );
354 } 395 }
355 396
356 #[test] 397 #[test]
357 fn test_complete_type() { 398 fn test_complete_type() {
358 check_scope_completion(r" 399 check_scope_completion(
400 r"
359 struct Foo; 401 struct Foo;
360 fn x() -> <|> 402 fn x() -> <|>
361 ", r#"[CompletionItem { label: "Foo", lookup: None, snippet: None }, 403 ",
362 CompletionItem { label: "x", lookup: None, snippet: None }]"#) 404 r#"[CompletionItem { label: "Foo", lookup: None, snippet: None },
405 CompletionItem { label: "x", lookup: None, snippet: None }]"#,
406 )
363 } 407 }
364 408
365 #[test] 409 #[test]
366 fn test_complete_shadowing() { 410 fn test_complete_shadowing() {
367 check_scope_completion(r" 411 check_scope_completion(
412 r"
368 fn foo() -> { 413 fn foo() -> {
369 let bar = 92; 414 let bar = 92;
370 { 415 {
@@ -372,15 +417,20 @@ mod tests {
372 <|> 417 <|>
373 } 418 }
374 } 419 }
375 ", r#"[CompletionItem { label: "bar", lookup: None, snippet: None }, 420 ",
376 CompletionItem { label: "foo", lookup: None, snippet: None }]"#) 421 r#"[CompletionItem { label: "bar", lookup: None, snippet: None },
422 CompletionItem { label: "foo", lookup: None, snippet: None }]"#,
423 )
377 } 424 }
378 425
379 #[test] 426 #[test]
380 fn test_complete_self() { 427 fn test_complete_self() {
381 check_scope_completion(r" 428 check_scope_completion(
429 r"
382 impl S { fn foo(&self) { <|> } } 430 impl S { fn foo(&self) { <|> } }
383 ", r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#) 431 ",
432 r#"[CompletionItem { label: "self", lookup: None, snippet: None }]"#,
433 )
384 } 434 }
385 435
386 #[test] 436 #[test]
diff --git a/crates/ra_editor/src/edit.rs b/crates/ra_editor/src/edit.rs
index 46e687319..c3149ec54 100644
--- a/crates/ra_editor/src/edit.rs
+++ b/crates/ra_editor/src/edit.rs
@@ -1,8 +1,5 @@
1use crate::{TextRange, TextUnit}; 1use crate::{TextRange, TextUnit};
2use ra_syntax::{ 2use ra_syntax::{text_utils::contains_offset_nonstrict, AtomEdit};
3 AtomEdit,
4 text_utils::contains_offset_nonstrict,
5};
6 3
7#[derive(Debug, Clone)] 4#[derive(Debug, Clone)]
8pub struct Edit { 5pub struct Edit {
@@ -11,7 +8,7 @@ pub struct Edit {
11 8
12#[derive(Debug)] 9#[derive(Debug)]
13pub struct EditBuilder { 10pub struct EditBuilder {
14 atoms: Vec<AtomEdit> 11 atoms: Vec<AtomEdit>,
15} 12}
16 13
17impl EditBuilder { 14impl EditBuilder {
@@ -36,7 +33,9 @@ impl EditBuilder {
36 Edit { atoms } 33 Edit { atoms }
37 } 34 }
38 pub fn invalidates_offset(&self, offset: TextUnit) -> bool { 35 pub fn invalidates_offset(&self, offset: TextUnit) -> bool {
39 self.atoms.iter().any(|atom| contains_offset_nonstrict(atom.delete, offset)) 36 self.atoms
37 .iter()
38 .any(|atom| contains_offset_nonstrict(atom.delete, offset))
40 } 39 }
41} 40}
42 41
@@ -74,7 +73,7 @@ impl Edit {
74 break; 73 break;
75 } 74 }
76 if offset < atom.delete.end() { 75 if offset < atom.delete.end() {
77 return None 76 return None;
78 } 77 }
79 res += TextUnit::of_str(&atom.insert); 78 res += TextUnit::of_str(&atom.insert);
80 res -= atom.delete.len(); 79 res -= atom.delete.len();
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs
index ab03a717e..9ee1df281 100644
--- a/crates/ra_editor/src/extend_selection.rs
+++ b/crates/ra_editor/src/extend_selection.rs
@@ -1,7 +1,8 @@
1use ra_syntax::{ 1use ra_syntax::{
2 File, TextRange, SyntaxNodeRef, TextUnit, Direction, 2 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset},
3 Direction, File,
3 SyntaxKind::*, 4 SyntaxKind::*,
4 algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node}, 5 SyntaxNodeRef, TextRange, TextUnit,
5}; 6};
6 7
7pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { 8pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> {
@@ -20,11 +21,11 @@ pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange>
20 LeafAtOffset::None => return None, 21 LeafAtOffset::None => return None,
21 LeafAtOffset::Single(l) => { 22 LeafAtOffset::Single(l) => {
22 if l.kind() == COMMENT { 23 if l.kind() == COMMENT {
23 extend_single_word_in_comment(l, offset).unwrap_or_else(||l.range()) 24 extend_single_word_in_comment(l, offset).unwrap_or_else(|| l.range())
24 } else { 25 } else {
25 l.range() 26 l.range()
26 } 27 }
27 }, 28 }
28 LeafAtOffset::Between(l, r) => pick_best(l, r).range(), 29 LeafAtOffset::Between(l, r) => pick_best(l, r).range(),
29 }; 30 };
30 return Some(leaf_range); 31 return Some(leaf_range);
@@ -66,7 +67,7 @@ fn extend_ws(root: SyntaxNodeRef, ws: SyntaxNodeRef, offset: TextUnit) -> TextRa
66 if let Some(node) = ws.next_sibling() { 67 if let Some(node) = ws.next_sibling() {
67 let start = match ws_prefix.rfind('\n') { 68 let start = match ws_prefix.rfind('\n') {
68 Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), 69 Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32),
69 None => node.range().start() 70 None => node.range().start(),
70 }; 71 };
71 let end = if root.text().char_at(node.range().end()) == Some('\n') { 72 let end = if root.text().char_at(node.range().end()) == Some('\n') {
72 node.range().end() + TextUnit::of_char('\n') 73 node.range().end() + TextUnit::of_char('\n')
@@ -94,10 +95,7 @@ fn extend_comments(node: SyntaxNodeRef) -> Option<TextRange> {
94 let prev = adj_comments(node, Direction::Prev); 95 let prev = adj_comments(node, Direction::Prev);
95 let next = adj_comments(node, Direction::Next); 96 let next = adj_comments(node, Direction::Next);
96 if prev != next { 97 if prev != next {
97 Some(TextRange::from_to( 98 Some(TextRange::from_to(prev.range().start(), next.range().end()))
98 prev.range().start(),
99 next.range().end(),
100 ))
101 } else { 99 } else {
102 None 100 None
103 } 101 }
@@ -109,7 +107,7 @@ fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef {
109 match node.kind() { 107 match node.kind() {
110 COMMENT => res = node, 108 COMMENT => res = node,
111 WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), 109 WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (),
112 _ => break 110 _ => break,
113 } 111 }
114 } 112 }
115 res 113 res
@@ -125,8 +123,7 @@ mod tests {
125 let file = File::parse(&before); 123 let file = File::parse(&before);
126 let mut range = TextRange::offset_len(cursor, 0.into()); 124 let mut range = TextRange::offset_len(cursor, 0.into());
127 for &after in afters { 125 for &after in afters {
128 range = extend_selection(&file, range) 126 range = extend_selection(&file, range).unwrap();
129 .unwrap();
130 let actual = &before[range]; 127 let actual = &before[range];
131 assert_eq!(after, actual); 128 assert_eq!(after, actual);
132 } 129 }
@@ -134,10 +131,7 @@ mod tests {
134 131
135 #[test] 132 #[test]
136 fn test_extend_selection_arith() { 133 fn test_extend_selection_arith() {
137 do_check( 134 do_check(r#"fn foo() { <|>1 + 1 }"#, &["1", "1 + 1", "{ 1 + 1 }"]);
138 r#"fn foo() { <|>1 + 1 }"#,
139 &["1", "1 + 1", "{ 1 + 1 }"],
140 );
141 } 135 }
142 136
143 #[test] 137 #[test]
@@ -149,7 +143,7 @@ impl S {
149 143
150 } 144 }
151}"#, 145}"#,
152 &[" fn foo() {\n\n }\n"] 146 &[" fn foo() {\n\n }\n"],
153 ); 147 );
154 } 148 }
155 149
@@ -165,7 +159,11 @@ struct B {
165 <|> 159 <|>
166} 160}
167 "#, 161 "#,
168 &["\n \n", "{\n \n}", "/// bla\n/// bla\nstruct B {\n \n}"] 162 &[
163 "\n \n",
164 "{\n \n}",
165 "/// bla\n/// bla\nstruct B {\n \n}",
166 ],
169 ) 167 )
170 } 168 }
171 169
@@ -181,7 +179,7 @@ fn bar(){}
181 179
182// fn foo(){} 180// fn foo(){}
183 "#, 181 "#,
184 &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"] 182 &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"],
185 ); 183 );
186 } 184 }
187 185
@@ -191,42 +189,34 @@ fn bar(){}
191 r#" 189 r#"
192fn main() { foo<|>+bar;} 190fn main() { foo<|>+bar;}
193 "#, 191 "#,
194 &["foo", "foo+bar"] 192 &["foo", "foo+bar"],
195 ); 193 );
196 do_check( 194 do_check(
197 r#" 195 r#"
198fn main() { foo+<|>bar;} 196fn main() { foo+<|>bar;}
199 "#, 197 "#,
200 &["bar", "foo+bar"] 198 &["bar", "foo+bar"],
201 ); 199 );
202 } 200 }
203 201
204 #[test] 202 #[test]
205 fn test_extend_selection_prefer_lifetimes() { 203 fn test_extend_selection_prefer_lifetimes() {
206 do_check( 204 do_check(r#"fn foo<<|>'a>() {}"#, &["'a", "<'a>"]);
207 r#"fn foo<<|>'a>() {}"#, 205 do_check(r#"fn foo<'a<|>>() {}"#, &["'a", "<'a>"]);
208 &["'a", "<'a>"]
209 );
210 do_check(
211 r#"fn foo<'a<|>>() {}"#,
212 &["'a", "<'a>"]
213 );
214 } 206 }
215 207
216 #[test] 208 #[test]
217 fn test_extend_selection_select_first_word() { 209 fn test_extend_selection_select_first_word() {
210 do_check(r#"// foo bar b<|>az quxx"#, &["baz", "// foo bar baz quxx"]);
218 do_check( 211 do_check(
219 r#"// foo bar b<|>az quxx"#, 212 r#"
220 &["baz", "// foo bar baz quxx"]
221 );
222 do_check(r#"
223impl S { 213impl S {
224 fn foo() { 214 fn foo() {
225 // hel<|>lo world 215 // hel<|>lo world
226 } 216 }
227} 217}
228 "#, 218 "#,
229 &["hello", "// hello world"] 219 &["hello", "// hello world"],
230 ); 220 );
231 } 221 }
232} 222}
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index a1699d449..e5bc0c4ee 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -1,11 +1,9 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast, 4 ast, AstNode, Direction, File,
5 AstNode,
6 File, TextRange, SyntaxNodeRef,
7 SyntaxKind::{self, *}, 5 SyntaxKind::{self, *},
8 Direction, 6 SyntaxNodeRef, TextRange,
9}; 7};
10 8
11#[derive(Debug, PartialEq, Eq)] 9#[derive(Debug, PartialEq, Eq)]
@@ -28,7 +26,10 @@ pub fn folding_ranges(file: &File) -> Vec<Fold> {
28 // Fold items that span multiple lines 26 // Fold items that span multiple lines
29 if let Some(kind) = fold_kind(node.kind()) { 27 if let Some(kind) = fold_kind(node.kind()) {
30 if has_newline(node) { 28 if has_newline(node) {
31 res.push(Fold { range: node.range(), kind }); 29 res.push(Fold {
30 range: node.range(),
31 kind,
32 });
32 } 33 }
33 } 34 }
34 35
@@ -37,8 +38,12 @@ pub fn folding_ranges(file: &File) -> Vec<Fold> {
37 continue; 38 continue;
38 } 39 }
39 if node.kind() == COMMENT { 40 if node.kind() == COMMENT {
40 contiguous_range_for_comment(node, &mut visited_comments) 41 contiguous_range_for_comment(node, &mut visited_comments).map(|range| {
41 .map(|range| res.push(Fold { range, kind: FoldKind::Comment })); 42 res.push(Fold {
43 range,
44 kind: FoldKind::Comment,
45 })
46 });
42 } 47 }
43 } 48 }
44 49
@@ -49,13 +54,11 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
49 match kind { 54 match kind {
50 COMMENT => Some(FoldKind::Comment), 55 COMMENT => Some(FoldKind::Comment),
51 USE_ITEM => Some(FoldKind::Imports), 56 USE_ITEM => Some(FoldKind::Imports),
52 _ => None 57 _ => None,
53 } 58 }
54} 59}
55 60
56fn has_newline( 61fn has_newline(node: SyntaxNodeRef) -> bool {
57 node: SyntaxNodeRef,
58) -> bool {
59 for descendant in node.descendants() { 62 for descendant in node.descendants() {
60 if let Some(ws) = ast::Whitespace::cast(descendant) { 63 if let Some(ws) = ast::Whitespace::cast(descendant) {
61 if ws.has_newlines() { 64 if ws.has_newlines() {
@@ -100,9 +103,7 @@ fn contiguous_range_for_comment<'a>(
100 // The comment group ends because either: 103 // The comment group ends because either:
101 // * An element of a different kind was reached 104 // * An element of a different kind was reached
102 // * A comment of a different flavor was reached 105 // * A comment of a different flavor was reached
103 _ => { 106 _ => break,
104 break
105 }
106 } 107 }
107 } 108 }
108 109
@@ -128,7 +129,11 @@ mod tests {
128 let folds = folding_ranges(&file); 129 let folds = folding_ranges(&file);
129 130
130 assert_eq!(folds.len(), ranges.len()); 131 assert_eq!(folds.len(), ranges.len());
131 for ((fold, range), fold_kind) in folds.into_iter().zip(ranges.into_iter()).zip(fold_kinds.into_iter()) { 132 for ((fold, range), fold_kind) in folds
133 .into_iter()
134 .zip(ranges.into_iter())
135 .zip(fold_kinds.into_iter())
136 {
132 assert_eq!(fold.range.start(), range.start()); 137 assert_eq!(fold.range.start(), range.start());
133 assert_eq!(fold.range.end(), range.end()); 138 assert_eq!(fold.range.end(), range.end());
134 assert_eq!(&fold.kind, fold_kind); 139 assert_eq!(&fold.kind, fold_kind);
@@ -181,5 +186,4 @@ fn main() {
181 do_check(text, folds); 186 do_check(text, folds);
182 } 187 }
183 188
184
185} 189}
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index bd61fd191..417080d90 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -1,44 +1,41 @@
1extern crate ra_syntax;
2extern crate superslice;
3extern crate itertools; 1extern crate itertools;
4extern crate join_to_string; 2extern crate join_to_string;
3extern crate ra_syntax;
5extern crate rustc_hash; 4extern crate rustc_hash;
5extern crate superslice;
6#[cfg(test)] 6#[cfg(test)]
7#[macro_use] 7#[macro_use]
8extern crate test_utils as _test_utils; 8extern crate test_utils as _test_utils;
9 9
10mod extend_selection;
11mod symbols;
12mod line_index;
13mod edit;
14mod folding_ranges;
15mod code_actions; 10mod code_actions;
16mod typing;
17mod completion; 11mod completion;
12mod edit;
13mod extend_selection;
14mod folding_ranges;
15mod line_index;
18mod scope; 16mod scope;
17mod symbols;
19#[cfg(test)] 18#[cfg(test)]
20mod test_utils; 19mod test_utils;
20mod typing;
21 21
22pub use self::{
23 code_actions::{add_derive, add_impl, flip_comma, introduce_variable, LocalEdit},
24 completion::{scope_completion, CompletionItem},
25 edit::{Edit, EditBuilder},
26 extend_selection::extend_selection,
27 folding_ranges::{folding_ranges, Fold, FoldKind},
28 line_index::{LineCol, LineIndex},
29 symbols::{file_structure, file_symbols, FileSymbol, StructureNode},
30 typing::{join_lines, on_enter, on_eq_typed},
31};
32pub use ra_syntax::AtomEdit;
22use ra_syntax::{ 33use ra_syntax::{
23 File, TextUnit, TextRange, SmolStr, SyntaxNodeRef,
24 ast::{self, AstNode, NameOwner},
25 algo::find_leaf_at_offset, 34 algo::find_leaf_at_offset,
35 ast::{self, AstNode, NameOwner},
36 File, SmolStr,
26 SyntaxKind::{self, *}, 37 SyntaxKind::{self, *},
27}; 38 SyntaxNodeRef, TextRange, TextUnit,
28pub use ra_syntax::AtomEdit;
29pub use self::{
30 line_index::{LineIndex, LineCol},
31 extend_selection::extend_selection,
32 symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
33 edit::{EditBuilder, Edit},
34 code_actions::{
35 LocalEdit,
36 flip_comma, add_derive, add_impl,
37 introduce_variable,
38 },
39 typing::{join_lines, on_eq_typed, on_enter},
40 completion::{scope_completion, CompletionItem},
41 folding_ranges::{Fold, FoldKind, folding_ranges}
42}; 39};
43 40
44#[derive(Debug)] 41#[derive(Debug)]
@@ -67,10 +64,7 @@ pub enum RunnableKind {
67 64
68pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { 65pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> {
69 const BRACES: &[SyntaxKind] = &[ 66 const BRACES: &[SyntaxKind] = &[
70 L_CURLY, R_CURLY, 67 L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE,
71 L_BRACK, R_BRACK,
72 L_PAREN, R_PAREN,
73 L_ANGLE, R_ANGLE,
74 ]; 68 ];
75 let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset) 69 let (brace_node, brace_idx) = find_leaf_at_offset(file.syntax(), offset)
76 .filter_map(|node| { 70 .filter_map(|node| {
@@ -80,7 +74,8 @@ pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> {
80 .next()?; 74 .next()?;
81 let parent = brace_node.parent()?; 75 let parent = brace_node.parent()?;
82 let matching_kind = BRACES[brace_idx ^ 1]; 76 let matching_kind = BRACES[brace_idx ^ 1];
83 let matching_node = parent.children() 77 let matching_node = parent
78 .children()
84 .find(|node| node.kind() == matching_kind)?; 79 .find(|node| node.kind() == matching_kind)?;
85 Some(matching_node.range().start()) 80 Some(matching_node.range().start())
86} 81}
@@ -108,10 +103,13 @@ pub fn highlight(file: &File) -> Vec<HighlightedRange> {
108} 103}
109 104
110pub fn diagnostics(file: &File) -> Vec<Diagnostic> { 105pub fn diagnostics(file: &File) -> Vec<Diagnostic> {
111 file.errors().into_iter().map(|err| Diagnostic { 106 file.errors()
112 range: TextRange::offset_len(err.offset, 1.into()), 107 .into_iter()
113 msg: "Syntax Error: ".to_string() + &err.msg, 108 .map(|err| Diagnostic {
114 }).collect() 109 range: TextRange::offset_len(err.offset, 1.into()),
110 msg: "Syntax Error: ".to_string() + &err.msg,
111 })
112 .collect()
115} 113}
116 114
117pub fn syntax_tree(file: &File) -> String { 115pub fn syntax_tree(file: &File) -> String {
@@ -119,7 +117,8 @@ pub fn syntax_tree(file: &File) -> String {
119} 117}
120 118
121pub fn runnables(file: &File) -> Vec<Runnable> { 119pub fn runnables(file: &File) -> Vec<Runnable> {
122 file.syntax().descendants() 120 file.syntax()
121 .descendants()
123 .filter_map(ast::FnDef::cast) 122 .filter_map(ast::FnDef::cast)
124 .filter_map(|f| { 123 .filter_map(|f| {
125 let name = f.name()?.text(); 124 let name = f.name()?.text();
@@ -127,7 +126,7 @@ pub fn runnables(file: &File) -> Vec<Runnable> {
127 RunnableKind::Bin 126 RunnableKind::Bin
128 } else if f.has_atom_attr("test") { 127 } else if f.has_atom_attr("test") {
129 RunnableKind::Test { 128 RunnableKind::Test {
130 name: name.to_string() 129 name: name.to_string(),
131 } 130 }
132 } else { 131 } else {
133 return None; 132 return None;
@@ -145,15 +144,18 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>(
145 offset: TextUnit, 144 offset: TextUnit,
146) -> Option<N> { 145) -> Option<N> {
147 let leaves = find_leaf_at_offset(syntax, offset); 146 let leaves = find_leaf_at_offset(syntax, offset);
148 let leaf = leaves.clone() 147 let leaf = leaves
148 .clone()
149 .find(|leaf| !leaf.kind().is_trivia()) 149 .find(|leaf| !leaf.kind().is_trivia())
150 .or_else(|| leaves.right_biased())?; 150 .or_else(|| leaves.right_biased())?;
151 leaf.ancestors() 151 leaf.ancestors().filter_map(N::cast).next()
152 .filter_map(N::cast)
153 .next()
154} 152}
155 153
156pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) -> Option<(SmolStr, TextRange)> { 154pub fn resolve_local_name(
155 file: &File,
156 offset: TextUnit,
157 name_ref: ast::NameRef,
158) -> Option<(SmolStr, TextRange)> {
157 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), offset)?; 159 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), offset)?;
158 let scopes = scope::FnScopes::new(fn_def); 160 let scopes = scope::FnScopes::new(fn_def);
159 let scope_entry = scope::resolve_local_name(name_ref, &scopes)?; 161 let scope_entry = scope::resolve_local_name(name_ref, &scopes)?;
@@ -164,15 +166,17 @@ pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef)
164#[cfg(test)] 166#[cfg(test)]
165mod tests { 167mod tests {
166 use super::*; 168 use super::*;
167 use crate::test_utils::{assert_eq_dbg, extract_offset, add_cursor}; 169 use crate::test_utils::{add_cursor, assert_eq_dbg, extract_offset};
168 170
169 #[test] 171 #[test]
170 fn test_highlighting() { 172 fn test_highlighting() {
171 let file = File::parse(r#" 173 let file = File::parse(
174 r#"
172// comment 175// comment
173fn main() {} 176fn main() {}
174 println!("Hello, {}!", 92); 177 println!("Hello, {}!", 92);
175"#); 178"#,
179 );
176 let hls = highlight(&file); 180 let hls = highlight(&file);
177 assert_eq_dbg( 181 assert_eq_dbg(
178 r#"[HighlightedRange { range: [1; 11), tag: "comment" }, 182 r#"[HighlightedRange { range: [1; 11), tag: "comment" },
@@ -187,7 +191,8 @@ fn main() {}
187 191
188 #[test] 192 #[test]
189 fn test_runnables() { 193 fn test_runnables() {
190 let file = File::parse(r#" 194 let file = File::parse(
195 r#"
191fn main() {} 196fn main() {}
192 197
193#[test] 198#[test]
@@ -196,7 +201,8 @@ fn test_foo() {}
196#[test] 201#[test]
197#[ignore] 202#[ignore]
198fn test_foo() {} 203fn test_foo() {}
199"#); 204"#,
205 );
200 let runnables = runnables(&file); 206 let runnables = runnables(&file);
201 assert_eq_dbg( 207 assert_eq_dbg(
202 r#"[Runnable { range: [1; 13), kind: Bin }, 208 r#"[Runnable { range: [1; 13), kind: Bin },
@@ -219,9 +225,6 @@ fn test_foo() {}
219 assert_eq_text!(after, &actual); 225 assert_eq_text!(after, &actual);
220 } 226 }
221 227
222 do_check( 228 do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }");
223 "struct Foo { a: i32, }<|>",
224 "struct Foo <|>{ a: i32, }",
225 );
226 } 229 }
227} 230}
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs
index 95d64b8a8..da0f2a7f7 100644
--- a/crates/ra_editor/src/line_index.rs
+++ b/crates/ra_editor/src/line_index.rs
@@ -1,5 +1,5 @@
1use superslice::Ext;
2use crate::TextUnit; 1use crate::TextUnit;
2use superslice::Ext;
3 3
4#[derive(Clone, Debug, Hash, PartialEq, Eq)] 4#[derive(Clone, Debug, Hash, PartialEq, Eq)]
5pub struct LineIndex { 5pub struct LineIndex {
@@ -29,7 +29,10 @@ impl LineIndex {
29 let line = self.newlines.upper_bound(&offset) - 1; 29 let line = self.newlines.upper_bound(&offset) - 1;
30 let line_start_offset = self.newlines[line]; 30 let line_start_offset = self.newlines[line];
31 let col = offset - line_start_offset; 31 let col = offset - line_start_offset;
32 return LineCol { line: line as u32, col }; 32 return LineCol {
33 line: line as u32,
34 col,
35 };
33 } 36 }
34 37
35 pub fn offset(&self, line_col: LineCol) -> TextUnit { 38 pub fn offset(&self, line_col: LineCol) -> TextUnit {
@@ -42,21 +45,105 @@ impl LineIndex {
42fn test_line_index() { 45fn test_line_index() {
43 let text = "hello\nworld"; 46 let text = "hello\nworld";
44 let index = LineIndex::new(text); 47 let index = LineIndex::new(text);
45 assert_eq!(index.line_col(0.into()), LineCol { line: 0, col: 0.into() }); 48 assert_eq!(
46 assert_eq!(index.line_col(1.into()), LineCol { line: 0, col: 1.into() }); 49 index.line_col(0.into()),
47 assert_eq!(index.line_col(5.into()), LineCol { line: 0, col: 5.into() }); 50 LineCol {
48 assert_eq!(index.line_col(6.into()), LineCol { line: 1, col: 0.into() }); 51 line: 0,
49 assert_eq!(index.line_col(7.into()), LineCol { line: 1, col: 1.into() }); 52 col: 0.into()
50 assert_eq!(index.line_col(8.into()), LineCol { line: 1, col: 2.into() }); 53 }
51 assert_eq!(index.line_col(10.into()), LineCol { line: 1, col: 4.into() }); 54 );
52 assert_eq!(index.line_col(11.into()), LineCol { line: 1, col: 5.into() }); 55 assert_eq!(
53 assert_eq!(index.line_col(12.into()), LineCol { line: 1, col: 6.into() }); 56 index.line_col(1.into()),
57 LineCol {
58 line: 0,
59 col: 1.into()
60 }
61 );
62 assert_eq!(
63 index.line_col(5.into()),
64 LineCol {
65 line: 0,
66 col: 5.into()
67 }
68 );
69 assert_eq!(
70 index.line_col(6.into()),
71 LineCol {
72 line: 1,
73 col: 0.into()
74 }
75 );
76 assert_eq!(
77 index.line_col(7.into()),
78 LineCol {
79 line: 1,
80 col: 1.into()
81 }
82 );
83 assert_eq!(
84 index.line_col(8.into()),
85 LineCol {
86 line: 1,
87 col: 2.into()
88 }
89 );
90 assert_eq!(
91 index.line_col(10.into()),
92 LineCol {
93 line: 1,
94 col: 4.into()
95 }
96 );
97 assert_eq!(
98 index.line_col(11.into()),
99 LineCol {
100 line: 1,
101 col: 5.into()
102 }
103 );
104 assert_eq!(
105 index.line_col(12.into()),
106 LineCol {
107 line: 1,
108 col: 6.into()
109 }
110 );
54 111
55 let text = "\nhello\nworld"; 112 let text = "\nhello\nworld";
56 let index = LineIndex::new(text); 113 let index = LineIndex::new(text);
57 assert_eq!(index.line_col(0.into()), LineCol { line: 0, col: 0.into() }); 114 assert_eq!(
58 assert_eq!(index.line_col(1.into()), LineCol { line: 1, col: 0.into() }); 115 index.line_col(0.into()),
59 assert_eq!(index.line_col(2.into()), LineCol { line: 1, col: 1.into() }); 116 LineCol {
60 assert_eq!(index.line_col(6.into()), LineCol { line: 1, col: 5.into() }); 117 line: 0,
61 assert_eq!(index.line_col(7.into()), LineCol { line: 2, col: 0.into() }); 118 col: 0.into()
119 }
120 );
121 assert_eq!(
122 index.line_col(1.into()),
123 LineCol {
124 line: 1,
125 col: 0.into()
126 }
127 );
128 assert_eq!(
129 index.line_col(2.into()),
130 LineCol {
131 line: 1,
132 col: 1.into()
133 }
134 );
135 assert_eq!(
136 index.line_col(6.into()),
137 LineCol {
138 line: 1,
139 col: 5.into()
140 }
141 );
142 assert_eq!(
143 index.line_col(7.into()),
144 LineCol {
145 line: 2,
146 col: 0.into()
147 }
148 );
62} 149}
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs
index 99d698b60..9088e5a60 100644
--- a/crates/ra_editor/src/scope/fn_scope.rs
+++ b/crates/ra_editor/src/scope/fn_scope.rs
@@ -1,10 +1,11 @@
1use std::fmt; 1use std::fmt;
2
2use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
3 4
4use ra_syntax::{ 5use ra_syntax::{
5 SyntaxNodeRef, SyntaxNode, SmolStr, AstNode, 6 algo::generate,
6 ast::{self, NameOwner, LoopBodyOwner, ArgListOwner}, 7 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
7 algo::{generate} 8 AstNode, SmolStr, SyntaxNode, SyntaxNodeRef,
8}; 9};
9 10
10type ScopeId = usize; 11type ScopeId = usize;
@@ -19,11 +20,12 @@ pub struct FnScopes {
19impl FnScopes { 20impl FnScopes {
20 pub fn new(fn_def: ast::FnDef) -> FnScopes { 21 pub fn new(fn_def: ast::FnDef) -> FnScopes {
21 let mut scopes = FnScopes { 22 let mut scopes = FnScopes {
22 self_param: fn_def.param_list() 23 self_param: fn_def
24 .param_list()
23 .and_then(|it| it.self_param()) 25 .and_then(|it| it.self_param())
24 .map(|it| it.syntax().owned()), 26 .map(|it| it.syntax().owned()),
25 scopes: Vec::new(), 27 scopes: Vec::new(),
26 scope_for: FxHashMap::default() 28 scope_for: FxHashMap::default(),
27 }; 29 };
28 let root = scopes.root_scope(); 30 let root = scopes.root_scope();
29 scopes.add_params_bindings(root, fn_def.param_list()); 31 scopes.add_params_bindings(root, fn_def.param_list());
@@ -35,27 +37,38 @@ impl FnScopes {
35 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { 37 pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
36 &self.scopes[scope].entries 38 &self.scopes[scope].entries
37 } 39 }
38 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a { 40 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
39 generate(self.scope_for(node), move |&scope| self.scopes[scope].parent) 41 generate(self.scope_for(node), move |&scope| {
42 self.scopes[scope].parent
43 })
40 } 44 }
41 fn root_scope(&mut self) -> ScopeId { 45 fn root_scope(&mut self) -> ScopeId {
42 let res = self.scopes.len(); 46 let res = self.scopes.len();
43 self.scopes.push(ScopeData { parent: None, entries: vec![] }); 47 self.scopes.push(ScopeData {
48 parent: None,
49 entries: vec![],
50 });
44 res 51 res
45 } 52 }
46 fn new_scope(&mut self, parent: ScopeId) -> ScopeId { 53 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
47 let res = self.scopes.len(); 54 let res = self.scopes.len();
48 self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] }); 55 self.scopes.push(ScopeData {
56 parent: Some(parent),
57 entries: vec![],
58 });
49 res 59 res
50 } 60 }
51 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { 61 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
52 let entries = pat.syntax().descendants() 62 let entries = pat
63 .syntax()
64 .descendants()
53 .filter_map(ast::BindPat::cast) 65 .filter_map(ast::BindPat::cast)
54 .filter_map(ScopeEntry::new); 66 .filter_map(ScopeEntry::new);
55 self.scopes[scope].entries.extend(entries); 67 self.scopes[scope].entries.extend(entries);
56 } 68 }
57 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { 69 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
58 params.into_iter() 70 params
71 .into_iter()
59 .flat_map(|it| it.params()) 72 .flat_map(|it| it.params())
60 .filter_map(|it| it.pat()) 73 .filter_map(|it| it.pat())
61 .for_each(|it| self.add_bindings(scope, it)); 74 .for_each(|it| self.add_bindings(scope, it));
@@ -71,34 +84,33 @@ impl FnScopes {
71} 84}
72 85
73pub struct ScopeEntry { 86pub struct ScopeEntry {
74 syntax: SyntaxNode 87 syntax: SyntaxNode,
75} 88}
76 89
77impl ScopeEntry { 90impl ScopeEntry {
78 fn new(pat: ast::BindPat) -> Option<ScopeEntry> { 91 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
79 if pat.name().is_some() { 92 if pat.name().is_some() {
80 Some(ScopeEntry { syntax: pat.syntax().owned() }) 93 Some(ScopeEntry {
94 syntax: pat.syntax().owned(),
95 })
81 } else { 96 } else {
82 None 97 None
83 } 98 }
84 } 99 }
85 pub fn name(&self) -> SmolStr { 100 pub fn name(&self) -> SmolStr {
86 self.ast().name() 101 self.ast().name().unwrap().text()
87 .unwrap()
88 .text()
89 } 102 }
90 pub fn ast(&self) -> ast::BindPat { 103 pub fn ast(&self) -> ast::BindPat {
91 ast::BindPat::cast(self.syntax.borrowed()) 104 ast::BindPat::cast(self.syntax.borrowed()).unwrap()
92 .unwrap()
93 } 105 }
94} 106}
95 107
96impl fmt::Debug for ScopeEntry { 108impl fmt::Debug for ScopeEntry {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 109 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 f.debug_struct("ScopeEntry") 110 f.debug_struct("ScopeEntry")
99 .field("name", &self.name()) 111 .field("name", &self.name())
100 .field("syntax", &self.syntax) 112 .field("syntax", &self.syntax)
101 .finish() 113 .finish()
102 } 114 }
103} 115}
104 116
@@ -132,16 +144,16 @@ fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: Sco
132fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { 144fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
133 match expr { 145 match expr {
134 ast::Expr::IfExpr(e) => { 146 ast::Expr::IfExpr(e) => {
135 let cond_scope = e.condition().and_then(|cond| { 147 let cond_scope = e
136 compute_cond_scopes(cond, scopes, scope) 148 .condition()
137 }); 149 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
138 if let Some(block) = e.then_branch() { 150 if let Some(block) = e.then_branch() {
139 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); 151 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
140 } 152 }
141 if let Some(block) = e.else_branch() { 153 if let Some(block) = e.else_branch() {
142 compute_block_scopes(block, scopes, scope); 154 compute_block_scopes(block, scopes, scope);
143 } 155 }
144 }, 156 }
145 ast::Expr::BlockExpr(e) => { 157 ast::Expr::BlockExpr(e) => {
146 if let Some(block) = e.block() { 158 if let Some(block) = e.block() {
147 compute_block_scopes(block, scopes, scope); 159 compute_block_scopes(block, scopes, scope);
@@ -153,9 +165,9 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
153 } 165 }
154 } 166 }
155 ast::Expr::WhileExpr(e) => { 167 ast::Expr::WhileExpr(e) => {
156 let cond_scope = e.condition().and_then(|cond| { 168 let cond_scope = e
157 compute_cond_scopes(cond, scopes, scope) 169 .condition()
158 }); 170 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
159 if let Some(block) = e.loop_body() { 171 if let Some(block) = e.loop_body() {
160 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); 172 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
161 } 173 }
@@ -201,25 +213,31 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
201 } 213 }
202 } 214 }
203 } 215 }
204 _ => { 216 _ => expr
205 expr.syntax().children() 217 .syntax()
206 .filter_map(ast::Expr::cast) 218 .children()
207 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)) 219 .filter_map(ast::Expr::cast)
208 } 220 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
209 }; 221 };
210 222
211 fn compute_call_scopes( 223 fn compute_call_scopes(
212 receiver: Option<ast::Expr>, 224 receiver: Option<ast::Expr>,
213 arg_list: Option<ast::ArgList>, 225 arg_list: Option<ast::ArgList>,
214 scopes: &mut FnScopes, scope: ScopeId, 226 scopes: &mut FnScopes,
227 scope: ScopeId,
215 ) { 228 ) {
216 arg_list.into_iter() 229 arg_list
230 .into_iter()
217 .flat_map(|it| it.args()) 231 .flat_map(|it| it.args())
218 .chain(receiver) 232 .chain(receiver)
219 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)); 233 .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
220 } 234 }
221 235
222 fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> { 236 fn compute_cond_scopes(
237 cond: ast::Condition,
238 scopes: &mut FnScopes,
239 scope: ScopeId,
240 ) -> Option<ScopeId> {
223 if let Some(expr) = cond.expr() { 241 if let Some(expr) = cond.expr() {
224 compute_expr_scopes(expr, scopes, scope); 242 compute_expr_scopes(expr, scopes, scope);
225 } 243 }
@@ -236,14 +254,18 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
236#[derive(Debug)] 254#[derive(Debug)]
237struct ScopeData { 255struct ScopeData {
238 parent: Option<ScopeId>, 256 parent: Option<ScopeId>,
239 entries: Vec<ScopeEntry> 257 entries: Vec<ScopeEntry>,
240} 258}
241 259
242pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option<&'a ScopeEntry> { 260pub fn resolve_local_name<'a>(
261 name_ref: ast::NameRef,
262 scopes: &'a FnScopes,
263) -> Option<&'a ScopeEntry> {
243 use rustc_hash::FxHashSet; 264 use rustc_hash::FxHashSet;
244 265
245 let mut shadowed = FxHashSet::default(); 266 let mut shadowed = FxHashSet::default();
246 let ret = scopes.scope_chain(name_ref.syntax()) 267 let ret = scopes
268 .scope_chain(name_ref.syntax())
247 .flat_map(|scope| scopes.entries(scope).iter()) 269 .flat_map(|scope| scopes.entries(scope).iter())
248 .filter(|entry| shadowed.insert(entry.name())) 270 .filter(|entry| shadowed.insert(entry.name()))
249 .filter(|entry| entry.name() == name_ref.text()) 271 .filter(|entry| entry.name() == name_ref.text())
@@ -255,8 +277,8 @@ pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> O
255#[cfg(test)] 277#[cfg(test)]
256mod tests { 278mod tests {
257 use super::*; 279 use super::*;
258 use ra_syntax::File;
259 use crate::{find_node_at_offset, test_utils::extract_offset}; 280 use crate::{find_node_at_offset, test_utils::extract_offset};
281 use ra_syntax::File;
260 282
261 fn do_check(code: &str, expected: &[&str]) { 283 fn do_check(code: &str, expected: &[&str]) {
262 let (off, code) = extract_offset(code); 284 let (off, code) = extract_offset(code);
@@ -272,7 +294,8 @@ mod tests {
272 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 294 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
273 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 295 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
274 let scopes = FnScopes::new(fn_def); 296 let scopes = FnScopes::new(fn_def);
275 let actual = scopes.scope_chain(marker.syntax()) 297 let actual = scopes
298 .scope_chain(marker.syntax())
276 .flat_map(|scope| scopes.entries(scope)) 299 .flat_map(|scope| scopes.entries(scope))
277 .map(|it| it.name()) 300 .map(|it| it.name())
278 .collect::<Vec<_>>(); 301 .collect::<Vec<_>>();
@@ -281,7 +304,8 @@ mod tests {
281 304
282 #[test] 305 #[test]
283 fn test_lambda_scope() { 306 fn test_lambda_scope() {
284 do_check(r" 307 do_check(
308 r"
285 fn quux(foo: i32) { 309 fn quux(foo: i32) {
286 let f = |bar, baz: i32| { 310 let f = |bar, baz: i32| {
287 <|> 311 <|>
@@ -293,7 +317,8 @@ mod tests {
293 317
294 #[test] 318 #[test]
295 fn test_call_scope() { 319 fn test_call_scope() {
296 do_check(r" 320 do_check(
321 r"
297 fn quux() { 322 fn quux() {
298 f(|x| <|> ); 323 f(|x| <|> );
299 }", 324 }",
@@ -303,7 +328,8 @@ mod tests {
303 328
304 #[test] 329 #[test]
305 fn test_metod_call_scope() { 330 fn test_metod_call_scope() {
306 do_check(r" 331 do_check(
332 r"
307 fn quux() { 333 fn quux() {
308 z.f(|x| <|> ); 334 z.f(|x| <|> );
309 }", 335 }",
@@ -313,7 +339,8 @@ mod tests {
313 339
314 #[test] 340 #[test]
315 fn test_loop_scope() { 341 fn test_loop_scope() {
316 do_check(r" 342 do_check(
343 r"
317 fn quux() { 344 fn quux() {
318 loop { 345 loop {
319 let x = (); 346 let x = ();
@@ -326,7 +353,8 @@ mod tests {
326 353
327 #[test] 354 #[test]
328 fn test_match() { 355 fn test_match() {
329 do_check(r" 356 do_check(
357 r"
330 fn quux() { 358 fn quux() {
331 match () { 359 match () {
332 Some(x) => { 360 Some(x) => {
@@ -340,7 +368,8 @@ mod tests {
340 368