diff options
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] |
64 | extern crate failure; | 63 | extern crate failure; |
65 | #[macro_use] | 64 | #[macro_use] |
@@ -74,16 +73,16 @@ extern crate languageserver_types; | |||
74 | mod msg; | 73 | mod msg; |
75 | mod stdio; | 74 | mod stdio; |
76 | 75 | ||
77 | use crossbeam_channel::{Sender, Receiver}; | 76 | use crossbeam_channel::{Receiver, Sender}; |
78 | use languageserver_types::{ | 77 | use 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 | ||
84 | pub type Result<T> = ::std::result::Result<T, failure::Error>; | 83 | pub type Result<T> = ::std::result::Result<T, failure::Error>; |
85 | pub use { | 84 | pub 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 @@ | |||
1 | use std::io::{BufRead, Write}; | 1 | use std::io::{BufRead, Write}; |
2 | 2 | ||
3 | use serde_json::{Value, from_str, to_string, from_value, to_value}; | 3 | use languageserver_types::{notification::Notification, request::Request}; |
4 | use serde::{Serialize, de::DeserializeOwned}; | 4 | use serde::{de::DeserializeOwned, Serialize}; |
5 | use languageserver_types::{ | 5 | use serde_json::{from_str, from_value, to_string, to_value, Value}; |
6 | request::Request, | ||
7 | notification::Notification, | ||
8 | }; | ||
9 | 6 | ||
10 | use Result; | 7 | use 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 | ||
116 | impl RawResponse { | 116 | impl 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 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | io::{stdin, stdout}, | ||
2 | thread, | 3 | thread, |
3 | io::{ | ||
4 | stdout, stdin, | ||
5 | }, | ||
6 | }; | 4 | }; |
7 | 5 | ||
8 | use crossbeam_channel::{Receiver, Sender, bounded}; | 6 | use crossbeam_channel::{bounded, Receiver, Sender}; |
9 | 7 | ||
10 | use {RawMessage, Result}; | 8 | use {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 @@ | |||
1 | use std::{ | ||
2 | fmt, | ||
3 | sync::Arc, | ||
4 | hash::{Hash, Hasher}, | ||
5 | }; | ||
6 | use salsa; | ||
7 | use rustc_hash::FxHashSet; | ||
8 | use ra_syntax::File; | ||
9 | use ra_editor::{LineIndex}; | ||
10 | use crate::{ | 1 | use 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 | }; |
6 | use ra_editor::LineIndex; | ||
7 | use ra_syntax::File; | ||
8 | use rustc_hash::FxHashSet; | ||
9 | use salsa; | ||
10 | |||
11 | use std::{ | ||
12 | fmt, | ||
13 | hash::{Hash, Hasher}, | ||
14 | sync::Arc, | ||
15 | }; | ||
15 | 16 | ||
16 | #[derive(Default)] | 17 | #[derive(Default)] |
17 | pub(crate) struct RootDatabase { | 18 | pub(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 @@ | |||
1 | use std::{ | 1 | use crate::{imp::FileResolverImp, FileId}; |
2 | collections::BTreeMap, | ||
3 | }; | ||
4 | use relative_path::RelativePathBuf; | ||
5 | use ra_syntax::{ | 2 | use 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 | }; | ||
10 | use crate::{ | ||
11 | FileId, | ||
12 | imp::FileResolverImp, | ||
13 | }; | 6 | }; |
7 | use relative_path::RelativePathBuf; | ||
8 | |||
9 | use std::collections::BTreeMap; | ||
14 | 10 | ||
15 | #[derive(Debug, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, PartialEq, Eq, Hash)] |
16 | pub struct ModuleDescriptor { | 12 | pub struct ModuleDescriptor { |
17 | pub submodules: Vec<Submodule> | 13 | pub submodules: Vec<Submodule>, |
18 | } | 14 | } |
19 | 15 | ||
20 | impl ModuleDescriptor { | 16 | impl 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 | ||
29 | fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item=(SmolStr, ast::Module<'a>)> { | 24 | fn 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); | |||
56 | struct NodeData { | 49 | struct 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)] |
74 | pub enum Problem { | 66 | pub 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 | ||
84 | impl ModuleTreeDescriptor { | 76 | impl 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 | |||
189 | fn resolve_submodule( | 193 | fn 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)] |
224 | pub struct FnDescriptor { | 228 | pub 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 @@ | |||
1 | use std::{ | 1 | use 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 | ||
11 | use relative_path::RelativePath; | 9 | use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit}; |
12 | use rustc_hash::FxHashSet; | ||
13 | use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name}; | ||
14 | use ra_syntax::{ | 10 | use 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 | }; |
16 | use relative_path::RelativePath; | ||
17 | use rustc_hash::FxHashSet; | ||
19 | 18 | ||
20 | use crate::{ | 19 | use 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)] |
28 | pub(crate) struct FileResolverImp { | 27 | pub(crate) struct FileResolverImp { |
29 | inner: Arc<FileResolver> | 28 | inner: Arc<FileResolver>, |
30 | } | 29 | } |
31 | 30 | ||
32 | impl PartialEq for FileResolverImp { | 31 | impl PartialEq for FileResolverImp { |
@@ -35,8 +34,7 @@ impl PartialEq for FileResolverImp { | |||
35 | } | 34 | } |
36 | } | 35 | } |
37 | 36 | ||
38 | impl Eq for FileResolverImp { | 37 | impl Eq for FileResolverImp {} |
39 | } | ||
40 | 38 | ||
41 | impl Hash for FileResolverImp { | 39 | impl 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)] |
79 | pub(crate) struct AnalysisHostImpl { | 83 | pub(crate) struct AnalysisHostImpl { |
80 | data: WorldData | 84 | data: WorldData, |
81 | } | 85 | } |
82 | 86 | ||
83 | impl AnalysisHostImpl { | 87 | impl 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 | ||
416 | impl CrateGraph { | 458 | impl 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 | ||
425 | enum FnCallNode<'a> { | 468 | enum 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 | ||
430 | impl<'a> FnCallNode<'a> { | 473 | impl<'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 | ||
28 | impl JobToken { | 33 | impl 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 @@ | |||
1 | extern crate parking_lot; | 1 | extern crate parking_lot; |
2 | #[macro_use] | 2 | #[macro_use] |
3 | extern crate log; | 3 | extern crate log; |
4 | extern crate fst; | ||
4 | extern crate once_cell; | 5 | extern crate once_cell; |
5 | extern crate ra_syntax; | ||
6 | extern crate ra_editor; | 6 | extern crate ra_editor; |
7 | extern crate fst; | 7 | extern crate ra_syntax; |
8 | extern crate rayon; | 8 | extern crate rayon; |
9 | extern crate relative_path; | 9 | extern crate relative_path; |
10 | #[macro_use] | 10 | #[macro_use] |
11 | extern crate crossbeam_channel; | 11 | extern crate crossbeam_channel; |
12 | extern crate im; | 12 | extern crate im; |
13 | extern crate salsa; | ||
14 | extern crate rustc_hash; | 13 | extern crate rustc_hash; |
14 | extern crate salsa; | ||
15 | 15 | ||
16 | mod symbol_index; | 16 | mod db; |
17 | mod module_map; | 17 | mod descriptors; |
18 | mod imp; | 18 | mod imp; |
19 | mod job; | 19 | mod job; |
20 | mod module_map; | ||
20 | mod roots; | 21 | mod roots; |
21 | mod db; | 22 | mod symbol_index; |
22 | mod descriptors; | ||
23 | 23 | ||
24 | use std::{ | 24 | use std::{fmt::Debug, sync::Arc}; |
25 | sync::Arc, | ||
26 | fmt::Debug, | ||
27 | }; | ||
28 | 25 | ||
26 | use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp}; | ||
27 | use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; | ||
29 | use relative_path::{RelativePath, RelativePathBuf}; | 28 | use relative_path::{RelativePath, RelativePathBuf}; |
30 | use ra_syntax::{File, TextRange, TextUnit, AtomEdit}; | ||
31 | use rustc_hash::FxHashMap; | 29 | use rustc_hash::FxHashMap; |
32 | use crate::imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp}; | ||
33 | 30 | ||
34 | pub use ra_editor::{ | ||
35 | StructureNode, LineIndex, FileSymbol, | ||
36 | Runnable, RunnableKind, HighlightedRange, CompletionItem, | ||
37 | Fold, FoldKind | ||
38 | }; | ||
39 | pub use crate::{ | 31 | pub use crate::{ |
40 | job::{JobToken, JobHandle}, | ||
41 | descriptors::FnDescriptor, | 32 | descriptors::FnDescriptor, |
33 | job::{JobHandle, JobToken}, | ||
34 | }; | ||
35 | pub 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)] |
61 | pub struct AnalysisHost { | 57 | pub struct AnalysisHost { |
62 | imp: AnalysisHostImpl | 58 | imp: AnalysisHostImpl, |
63 | } | 59 | } |
64 | 60 | ||
65 | impl AnalysisHost { | 61 | impl 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)] |
165 | pub struct Analysis { | 165 | pub struct Analysis { |
166 | imp: AnalysisImpl | 166 | imp: AnalysisImpl, |
167 | } | 167 | } |
168 | 168 | ||
169 | impl Analysis { | 169 | impl 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)] |
249 | pub struct LibraryData { | 263 | pub struct LibraryData { |
250 | root: roots::ReadonlySourceRoot | 264 | root: roots::ReadonlySourceRoot, |
251 | } | 265 | } |
252 | 266 | ||
253 | impl LibraryData { | 267 | impl 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 @@ | |||
1 | use std::sync::Arc; | ||
2 | use crate::{ | 1 | use crate::{ |
3 | FileId, | 2 | db::SyntaxDatabase, |
4 | db::{SyntaxDatabase}, | ||
5 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, | 3 | descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, |
4 | FileId, | ||
6 | }; | 5 | }; |
7 | 6 | ||
7 | use std::sync::Arc; | ||
8 | |||
8 | salsa::query_group! { | 9 | salsa::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 | |||
20 | fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { | 20 | fn 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 @@ | |||
1 | use std::{ | 1 | use std::{panic, sync::Arc}; |
2 | sync::Arc, | ||
3 | panic, | ||
4 | }; | ||
5 | 2 | ||
6 | use once_cell::sync::OnceCell; | 3 | use once_cell::sync::OnceCell; |
7 | use rayon::prelude::*; | ||
8 | use salsa::Database; | ||
9 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
10 | use ra_editor::LineIndex; | 4 | use ra_editor::LineIndex; |
11 | use ra_syntax::File; | 5 | use ra_syntax::File; |
6 | use rayon::prelude::*; | ||
7 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
8 | use salsa::Database; | ||
12 | 9 | ||
13 | use crate::{ | 10 | use 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 | ||
22 | pub(crate) trait SourceRoot { | 19 | pub(crate) trait SourceRoot { |
@@ -35,7 +32,7 @@ pub(crate) struct WritableSourceRoot { | |||
35 | impl WritableSourceRoot { | 32 | impl 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 | ||
133 | impl ReadonlySourceRoot { | 131 | impl 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 @@ | |||
1 | use std::{ | 1 | use crate::{FileId, JobToken, Query}; |
2 | sync::Arc, | 2 | use fst::{self, Streamer}; |
3 | hash::{Hash, Hasher}, | 3 | use ra_editor::{file_symbols, FileSymbol}; |
4 | }; | ||
5 | use ra_editor::{FileSymbol, file_symbols}; | ||
6 | use ra_syntax::{ | 4 | use ra_syntax::{ |
7 | File, | 5 | File, |
8 | SyntaxKind::{self, *}, | 6 | SyntaxKind::{self, *}, |
9 | }; | 7 | }; |
10 | use fst::{self, Streamer}; | ||
11 | use rayon::prelude::*; | 8 | use rayon::prelude::*; |
12 | use crate::{Query, FileId, JobToken}; | 9 | |
10 | use std::{ | ||
11 | hash::{Hash, Hasher}, | ||
12 | sync::Arc, | ||
13 | }; | ||
13 | 14 | ||
14 | #[derive(Debug)] | 15 | #[derive(Debug)] |
15 | pub(crate) struct SymbolIndex { | 16 | pub(crate) struct SymbolIndex { |
@@ -23,8 +24,7 @@ impl PartialEq for SymbolIndex { | |||
23 | } | 24 | } |
24 | } | 25 | } |
25 | 26 | ||
26 | impl Eq for SymbolIndex { | 27 | impl Eq for SymbolIndex {} |
27 | } | ||
28 | 28 | ||
29 | impl Hash for SymbolIndex { | 29 | impl 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 | ||
35 | impl SymbolIndex { | 35 | impl 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 @@ | |||
1 | extern crate relative_path; | ||
2 | extern crate ra_analysis; | 1 | extern crate ra_analysis; |
3 | extern crate rustc_hash; | ||
4 | extern crate ra_editor; | 2 | extern crate ra_editor; |
5 | extern crate ra_syntax; | 3 | extern crate ra_syntax; |
4 | extern crate relative_path; | ||
5 | extern crate rustc_hash; | ||
6 | extern crate test_utils; | 6 | extern crate test_utils; |
7 | 7 | ||
8 | use std::{ | 8 | use std::sync::Arc; |
9 | sync::Arc, | ||
10 | }; | ||
11 | 9 | ||
12 | use rustc_hash::FxHashMap; | 10 | use ra_analysis::{ |
11 | Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle, | ||
12 | }; | ||
13 | use relative_path::{RelativePath, RelativePathBuf}; | 13 | use relative_path::{RelativePath, RelativePathBuf}; |
14 | use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId, FnDescriptor}; | 14 | use rustc_hash::FxHashMap; |
15 | use test_utils::{assert_eq_dbg, extract_offset}; | 15 | use test_utils::{assert_eq_dbg, extract_offset}; |
16 | 16 | ||
17 | #[derive(Debug)] | 17 | #[derive(Debug)] |
18 | struct FileMap(Vec<(FileId, RelativePathBuf)>); | 18 | struct FileMap(Vec<(FileId, RelativePathBuf)>); |
19 | 19 | ||
20 | impl FileMap { | 20 | impl 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] |
73 | fn test_resolve_module() { | 72 | fn 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() { | |||
114 | fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { | 107 | fn 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] |
124 | fn test_resolve_parent_module() { | 114 | fn 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] |
137 | fn test_resolve_crate_root() { | 124 | fn 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] |
162 | fn test_fn_signature_two_args_first() { | 143 | fn test_fn_signature_two_args_first() { |
163 | let (desc, param) = get_signature( | 144 | let (desc, param) = get_signature( |
164 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} | 145 | r#"fn foo(x: u32, y: u32) -> u32 {x + y} |
165 | fn bar() { foo(<|>3, ); }"#); | 146 | fn 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, ); }"#); | |||
174 | fn test_fn_signature_two_args_second() { | 156 | fn 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} |
177 | fn bar() { foo(3, <|>); }"#); | 159 | fn 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] |
186 | fn test_fn_signature_for_impl() { | 169 | fn test_fn_signature_for_impl() { |
187 | let (desc, param) = get_signature( | 170 | let (desc, param) = get_signature( |
188 | r#"struct F; impl F { pub fn new() { F{}} } | 171 | r#"struct F; impl F { pub fn new() { F{}} } |
189 | fn bar() {let _ : F = F::new(<|>);}"#); | 172 | fn 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] |
198 | fn test_fn_signature_for_method_self() { | 182 | fn test_fn_signature_for_method_self() { |
199 | let (desc, param) = get_signature( | 183 | let (desc, param) = get_signature( |
200 | r#"struct F; | 184 | r#"struct F; |
201 | impl F { | 185 | impl F { |
202 | pub fn new() -> F{ | 186 | pub fn new() -> F{ |
203 | F{} | 187 | F{} |
@@ -209,7 +193,8 @@ impl F { | |||
209 | fn bar() { | 193 | fn 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] |
221 | fn test_fn_signature_for_method_with_arg() { | 206 | fn test_fn_signature_for_method_with_arg() { |
222 | let (desc, param) = get_signature( | 207 | let (desc, param) = get_signature( |
223 | r#"struct F; | 208 | r#"struct F; |
224 | impl F { | 209 | impl F { |
225 | pub fn new() -> F{ | 210 | pub fn new() -> F{ |
226 | F{} | 211 | F{} |
@@ -232,7 +217,8 @@ impl F { | |||
232 | fn bar() { | 217 | fn 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] |
3 | extern crate failure; | 3 | extern crate failure; |
4 | extern crate join_to_string; | 4 | extern crate join_to_string; |
5 | extern crate ra_syntax; | ||
6 | extern crate ra_editor; | 5 | extern crate ra_editor; |
6 | extern crate ra_syntax; | ||
7 | extern crate tools; | 7 | extern crate tools; |
8 | 8 | ||
9 | use std::{ | 9 | use std::{fs, io::Read, path::Path, time::Instant}; |
10 | fs, io::Read, path::Path, | 10 | |
11 | time::Instant | ||
12 | }; | ||
13 | use clap::{App, Arg, SubCommand}; | 11 | use clap::{App, Arg, SubCommand}; |
14 | use join_to_string::join; | 12 | use join_to_string::join; |
13 | use ra_editor::{extend_selection, file_structure, syntax_tree}; | ||
14 | use ra_syntax::{File, TextRange}; | ||
15 | use tools::collect_tests; | 15 | use tools::collect_tests; |
16 | use ra_syntax::{TextRange, File}; | ||
17 | use ra_editor::{syntax_tree, file_structure, extend_selection}; | ||
18 | 16 | ||
19 | type Result<T> = ::std::result::Result<T, failure::Error>; | 17 | type 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 @@ | |||
1 | use join_to_string::join; | 1 | use join_to_string::join; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use 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 | ||
14 | use crate::{EditBuilder, Edit, find_node_at_offset}; | 11 | use crate::{find_node_at_offset, Edit, EditBuilder}; |
15 | 12 | ||
16 | #[derive(Debug)] | 13 | #[derive(Debug)] |
17 | pub struct LocalEdit { | 14 | pub 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 | ||
100 | pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> { | 100 | pub 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 | " |
192 | fn foo() { | 199 | fn foo() { |
193 | foo(<|>1 + 1<|>); | 200 | foo(<|>1 + 1<|>); |
194 | }", " | 201 | }", |
202 | " | ||
195 | fn foo() { | 203 | fn 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() { |
204 | check_action_range( | 212 | check_action_range( |
205 | " | 213 | " |
206 | fn foo() { | 214 | fn foo() { |
207 | <|>1 + 1<|>; | 215 | <|>1 + 1<|>; |
208 | }", " | 216 | }", |
217 | " | ||
209 | fn foo() { | 218 | fn 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 @@ | |||
1 | use rustc_hash::{FxHashMap, FxHashSet}; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use 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 | ||
12 | use crate::{ | 12 | use 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 | ||
27 | pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> { | 28 | pub 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 | 153 | fn complete_expr_keywords( | |
138 | fn 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 | ||
210 | fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) { | 235 | fn 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 | ||
225 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | 248 | fn 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 | ||
234 | fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { | 256 | fn 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 @@ | |||
1 | use crate::{TextRange, TextUnit}; | 1 | use crate::{TextRange, TextUnit}; |
2 | use ra_syntax::{ | 2 | use 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)] |
8 | pub struct Edit { | 5 | pub struct Edit { |
@@ -11,7 +8,7 @@ pub struct Edit { | |||
11 | 8 | ||
12 | #[derive(Debug)] | 9 | #[derive(Debug)] |
13 | pub struct EditBuilder { | 10 | pub struct EditBuilder { |
14 | atoms: Vec<AtomEdit> | 11 | atoms: Vec<AtomEdit>, |
15 | } | 12 | } |
16 | 13 | ||
17 | impl EditBuilder { | 14 | impl 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 @@ | |||
1 | use ra_syntax::{ | 1 | use 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 | ||
7 | pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { | 8 | pub 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#" |
192 | fn main() { foo<|>+bar;} | 190 | fn 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#" |
198 | fn main() { foo+<|>bar;} | 196 | fn 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#" | ||
223 | impl S { | 213 | impl 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 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use 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 | ||
56 | fn has_newline( | 61 | fn 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 @@ | |||
1 | extern crate ra_syntax; | ||
2 | extern crate superslice; | ||
3 | extern crate itertools; | 1 | extern crate itertools; |
4 | extern crate join_to_string; | 2 | extern crate join_to_string; |
3 | extern crate ra_syntax; | ||
5 | extern crate rustc_hash; | 4 | extern crate rustc_hash; |
5 | extern crate superslice; | ||
6 | #[cfg(test)] | 6 | #[cfg(test)] |
7 | #[macro_use] | 7 | #[macro_use] |
8 | extern crate test_utils as _test_utils; | 8 | extern crate test_utils as _test_utils; |
9 | 9 | ||
10 | mod extend_selection; | ||
11 | mod symbols; | ||
12 | mod line_index; | ||
13 | mod edit; | ||
14 | mod folding_ranges; | ||
15 | mod code_actions; | 10 | mod code_actions; |
16 | mod typing; | ||
17 | mod completion; | 11 | mod completion; |
12 | mod edit; | ||
13 | mod extend_selection; | ||
14 | mod folding_ranges; | ||
15 | mod line_index; | ||
18 | mod scope; | 16 | mod scope; |
17 | mod symbols; | ||
19 | #[cfg(test)] | 18 | #[cfg(test)] |
20 | mod test_utils; | 19 | mod test_utils; |
20 | mod typing; | ||
21 | 21 | ||
22 | pub 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 | }; | ||
32 | pub use ra_syntax::AtomEdit; | ||
22 | use ra_syntax::{ | 33 | use 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, |
28 | pub use ra_syntax::AtomEdit; | ||
29 | pub 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 | ||
68 | pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { | 65 | pub 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 | ||
110 | pub fn diagnostics(file: &File) -> Vec<Diagnostic> { | 105 | pub 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 | ||
117 | pub fn syntax_tree(file: &File) -> String { | 115 | pub fn syntax_tree(file: &File) -> String { |
@@ -119,7 +117,8 @@ pub fn syntax_tree(file: &File) -> String { | |||
119 | } | 117 | } |
120 | 118 | ||
121 | pub fn runnables(file: &File) -> Vec<Runnable> { | 119 | pub 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 | ||
156 | pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) -> Option<(SmolStr, TextRange)> { | 154 | pub 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)] |
165 | mod tests { | 167 | mod 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 |
173 | fn main() {} | 176 | fn 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#" | ||
191 | fn main() {} | 196 | fn main() {} |
192 | 197 | ||
193 | #[test] | 198 | #[test] |
@@ -196,7 +201,8 @@ fn test_foo() {} | |||
196 | #[test] | 201 | #[test] |
197 | #[ignore] | 202 | #[ignore] |
198 | fn test_foo() {} | 203 | fn 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 @@ | |||
1 | use superslice::Ext; | ||
2 | use crate::TextUnit; | 1 | use crate::TextUnit; |
2 | use superslice::Ext; | ||
3 | 3 | ||
4 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] | 4 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
5 | pub struct LineIndex { | 5 | pub 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 { | |||
42 | fn test_line_index() { | 45 | fn 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 @@ | |||
1 | use std::fmt; | 1 | use std::fmt; |
2 | |||
2 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
3 | 4 | ||
4 | use ra_syntax::{ | 5 | use 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 | ||
10 | type ScopeId = usize; | 11 | type ScopeId = usize; |
@@ -19,11 +20,12 @@ pub struct FnScopes { | |||
19 | impl FnScopes { | 20 | impl 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 | ||
73 | pub struct ScopeEntry { | 86 | pub struct ScopeEntry { |
74 | syntax: SyntaxNode | 87 | syntax: SyntaxNode, |
75 | } | 88 | } |
76 | 89 | ||
77 | impl ScopeEntry { | 90 | impl 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 | ||
96 | impl fmt::Debug for ScopeEntry { | 108 | impl 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 | |||
132 | fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | 144 | fn 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)] |
237 | struct ScopeData { | 255 | struct ScopeData { |
238 | parent: Option<ScopeId>, | 256 | parent: Option<ScopeId>, |
239 | entries: Vec<ScopeEntry> | 257 | entries: Vec<ScopeEntry>, |
240 | } | 258 | } |
241 | 259 | ||
242 | pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> Option<&'a ScopeEntry> { | 260 | pub 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)] |
256 | mod tests { | 278 | mod 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 |