aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/completion.rs (renamed from crates/ra_analysis/src/completion/mod.rs)0
-rw-r--r--crates/ra_analysis/src/imp.rs39
-rw-r--r--crates/ra_analysis/src/lib.rs29
-rw-r--r--crates/ra_analysis/tests/tests.rs21
-rw-r--r--crates/ra_editor/src/extend_selection.rs27
-rw-r--r--crates/ra_editor/src/symbols.rs55
-rw-r--r--crates/ra_hir/src/function.rs (renamed from crates/ra_hir/src/function/mod.rs)0
-rw-r--r--crates/ra_hir/src/module.rs (renamed from crates/ra_hir/src/module/mod.rs)0
-rw-r--r--crates/ra_hir/src/module/imp.rs40
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs (renamed from crates/ra_lsp_server/src/main_loop/mod.rs)0
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs36
-rw-r--r--crates/ra_syntax/src/algo.rs (renamed from crates/ra_syntax/src/algo/mod.rs)0
-rw-r--r--crates/ra_syntax/src/ast.rs (renamed from crates/ra_syntax/src/ast/mod.rs)0
-rw-r--r--crates/ra_syntax/src/grammar.ron4
-rw-r--r--crates/ra_syntax/src/grammar.rs (renamed from crates/ra_syntax/src/grammar/mod.rs)0
-rw-r--r--crates/ra_syntax/src/grammar/expressions.rs (renamed from crates/ra_syntax/src/grammar/expressions/mod.rs)0
-rw-r--r--crates/ra_syntax/src/grammar/items.rs (renamed from crates/ra_syntax/src/grammar/items/mod.rs)0
-rw-r--r--crates/ra_syntax/src/lexer.rs (renamed from crates/ra_syntax/src/lexer/mod.rs)0
-rw-r--r--crates/ra_syntax/src/parser_impl.rs (renamed from crates/ra_syntax/src/parser_impl/mod.rs)0
-rw-r--r--crates/ra_syntax/src/string_lexing.rs (renamed from crates/ra_syntax/src/string_lexing/mod.rs)0
-rw-r--r--crates/ra_syntax/src/syntax_kinds.rs (renamed from crates/ra_syntax/src/syntax_kinds/mod.rs)0
-rw-r--r--crates/ra_syntax/src/syntax_kinds/generated.rs1
-rw-r--r--crates/ra_syntax/src/syntax_kinds/generated.rs.tera1
-rw-r--r--crates/ra_syntax/src/validation.rs (renamed from crates/ra_syntax/src/validation/mod.rs)0
-rw-r--r--crates/ra_syntax/src/yellow.rs (renamed from crates/ra_syntax/src/yellow/mod.rs)0
-rw-r--r--crates/tools/src/main.rs10
26 files changed, 202 insertions, 61 deletions
diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion.rs
index 0f154112a..0f154112a 100644
--- a/crates/ra_analysis/src/completion/mod.rs
+++ b/crates/ra_analysis/src/completion.rs
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 975afc145..03d17de0d 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -27,6 +27,7 @@ use crate::{
27 symbol_index::{SymbolIndex, SymbolsDatabase}, 27 symbol_index::{SymbolIndex, SymbolsDatabase},
28 AnalysisChange, Cancelable, CrateId, Diagnostic, FileId, 28 AnalysisChange, Cancelable, CrateId, Diagnostic, FileId,
29 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit, 29 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
30 ReferenceResolution,
30}; 31};
31 32
32#[derive(Debug, Default)] 33#[derive(Debug, Default)]
@@ -144,7 +145,7 @@ impl AnalysisImpl {
144 } else { 145 } else {
145 let files = &self.db.source_root(WORKSPACE).files; 146 let files = &self.db.source_root(WORKSPACE).files;
146 147
147 /// Need to wrap Snapshot to provide `Clon` impl for `map_with` 148 /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
148 struct Snap(salsa::Snapshot<db::RootDatabase>); 149 struct Snap(salsa::Snapshot<db::RootDatabase>);
149 impl Clone for Snap { 150 impl Clone for Snap {
150 fn clone(&self) -> Snap { 151 fn clone(&self) -> Snap {
@@ -164,7 +165,7 @@ impl AnalysisImpl {
164 .sweep(salsa::SweepStrategy::default().discard_values()); 165 .sweep(salsa::SweepStrategy::default().discard_values());
165 Ok(query.search(&buf)) 166 Ok(query.search(&buf))
166 } 167 }
167 /// This return `Vec`: a module may be included from several places. We 168 /// This returns `Vec` because a module may be included from several places. We
168 /// don't handle this case yet though, so the Vec has length at most one. 169 /// don't handle this case yet though, so the Vec has length at most one.
169 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 170 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
170 let descr = match source_binder::module_from_position(&*self.db, position)? { 171 let descr = match source_binder::module_from_position(&*self.db, position)? {
@@ -206,10 +207,11 @@ impl AnalysisImpl {
206 pub fn approximately_resolve_symbol( 207 pub fn approximately_resolve_symbol(
207 &self, 208 &self,
208 position: FilePosition, 209 position: FilePosition,
209 ) -> Cancelable<Vec<(FileId, FileSymbol)>> { 210 ) -> Cancelable<Option<ReferenceResolution>> {
210 let file = self.db.source_file(position.file_id); 211 let file = self.db.source_file(position.file_id);
211 let syntax = file.syntax(); 212 let syntax = file.syntax();
212 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 213 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
214 let mut rr = ReferenceResolution::new(name_ref.syntax().range());
213 if let Some(fn_descr) = source_binder::function_from_child_node( 215 if let Some(fn_descr) = source_binder::function_from_child_node(
214 &*self.db, 216 &*self.db,
215 position.file_id, 217 position.file_id,
@@ -218,22 +220,25 @@ impl AnalysisImpl {
218 let scope = fn_descr.scope(&*self.db); 220 let scope = fn_descr.scope(&*self.db);
219 // First try to resolve the symbol locally 221 // First try to resolve the symbol locally
220 if let Some(entry) = scope.resolve_local_name(name_ref) { 222 if let Some(entry) = scope.resolve_local_name(name_ref) {
221 let mut vec = vec![]; 223 rr.add_resolution(
222 vec.push((
223 position.file_id, 224 position.file_id,
224 FileSymbol { 225 FileSymbol {
225 name: entry.name().clone(), 226 name: entry.name().clone(),
226 node_range: entry.ptr().range(), 227 node_range: entry.ptr().range(),
227 kind: NAME, 228 kind: NAME,
228 }, 229 },
229 )); 230 );
230 return Ok(vec); 231 return Ok(Some(rr));
231 }; 232 };
232 } 233 }
233 // If that fails try the index based approach. 234 // If that fails try the index based approach.
234 return self.index_resolve(name_ref); 235 for (file_id, symbol) in self.index_resolve(name_ref)? {
236 rr.add_resolution(file_id, symbol);
237 }
238 return Ok(Some(rr));
235 } 239 }
236 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { 240 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
241 let mut rr = ReferenceResolution::new(name.syntax().range());
237 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 242 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
238 if module.has_semi() { 243 if module.has_semi() {
239 let parent_module = 244 let parent_module =
@@ -248,7 +253,8 @@ impl AnalysisImpl {
248 node_range: TextRange::offset_len(0.into(), 0.into()), 253 node_range: TextRange::offset_len(0.into(), 0.into()),
249 kind: MODULE, 254 kind: MODULE,
250 }; 255 };
251 return Ok(vec![(file_id, symbol)]); 256 rr.add_resolution(file_id, symbol);
257 return Ok(Some(rr));
252 } 258 }
253 } 259 }
254 _ => (), 260 _ => (),
@@ -256,7 +262,7 @@ impl AnalysisImpl {
256 } 262 }
257 } 263 }
258 } 264 }
259 Ok(vec![]) 265 Ok(None)
260 } 266 }
261 267
262 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 268 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
@@ -318,6 +324,19 @@ impl AnalysisImpl {
318 324
319 Ok(symbol.docs(&file)) 325 Ok(symbol.docs(&file))
320 } 326 }
327 pub fn doc_text_for(&self, file_id: FileId, symbol: FileSymbol) -> Cancelable<Option<String>> {
328 let file = self.db.source_file(file_id);
329 let result = match (symbol.description(&file), symbol.docs(&file)) {
330 (Some(desc), Some(docs)) => {
331 Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs)
332 }
333 (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"),
334 (None, Some(docs)) => Some(docs),
335 _ => None,
336 };
337
338 Ok(result)
339 }
321 340
322 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 341 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
323 let syntax = self.db.source_file(file_id); 342 let syntax = self.db.source_file(file_id);
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 4b8b10816..eaf24cb36 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -178,6 +178,30 @@ impl Query {
178 } 178 }
179} 179}
180 180
181/// Result of "goto def" query.
182#[derive(Debug)]
183pub struct ReferenceResolution {
184 /// The range of the reference itself. Client does not know what constitutes
185 /// a reference, it handles us only the offset. It's helpful to tell the
186 /// client where the reference was.
187 pub reference_range: TextRange,
188 /// What this reference resolves to.
189 pub resolves_to: Vec<(FileId, FileSymbol)>,
190}
191
192impl ReferenceResolution {
193 fn new(reference_range: TextRange) -> ReferenceResolution {
194 ReferenceResolution {
195 reference_range,
196 resolves_to: Vec::new(),
197 }
198 }
199
200 fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) {
201 self.resolves_to.push((file_id, symbol))
202 }
203}
204
181/// Analysis is a snapshot of a world state at a moment in time. It is the main 205/// Analysis is a snapshot of a world state at a moment in time. It is the main
182/// entry point for asking semantic information about the world. When the world 206/// entry point for asking semantic information about the world. When the world
183/// state is advanced using `AnalysisHost::apply_change` method, all existing 207/// state is advanced using `AnalysisHost::apply_change` method, all existing
@@ -236,7 +260,7 @@ impl Analysis {
236 pub fn approximately_resolve_symbol( 260 pub fn approximately_resolve_symbol(
237 &self, 261 &self,
238 position: FilePosition, 262 position: FilePosition,
239 ) -> Cancelable<Vec<(FileId, FileSymbol)>> { 263 ) -> Cancelable<Option<ReferenceResolution>> {
240 self.imp.approximately_resolve_symbol(position) 264 self.imp.approximately_resolve_symbol(position)
241 } 265 }
242 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 266 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
@@ -249,6 +273,9 @@ impl Analysis {
249 ) -> Cancelable<Option<String>> { 273 ) -> Cancelable<Option<String>> {
250 self.imp.doc_comment_for(file_id, symbol) 274 self.imp.doc_comment_for(file_id, symbol)
251 } 275 }
276 pub fn doc_text_for(&self, file_id: FileId, symbol: FileSymbol) -> Cancelable<Option<String>> {
277 self.imp.doc_text_for(file_id, symbol)
278 }
252 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 279 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
253 self.imp.parent_module(position) 280 self.imp.parent_module(position)
254 } 281 }
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 4ce2c5c85..889b568b9 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -21,9 +21,12 @@ fn approximate_resolve_works_in_items() {
21 ", 21 ",
22 ); 22 );
23 23
24 let symbols = analysis.approximately_resolve_symbol(pos).unwrap(); 24 let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
25 assert_eq_dbg( 25 assert_eq_dbg(
26 r#"[(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })]"#, 26 r#"ReferenceResolution {
27 reference_range: [23; 26),
28 resolves_to: [(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })]
29 }"#,
27 &symbols, 30 &symbols,
28 ); 31 );
29} 32}
@@ -39,9 +42,12 @@ fn test_resolve_module() {
39 ", 42 ",
40 ); 43 );
41 44
42 let symbols = analysis.approximately_resolve_symbol(pos).unwrap(); 45 let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
43 assert_eq_dbg( 46 assert_eq_dbg(
44 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, 47 r#"ReferenceResolution {
48 reference_range: [4; 7),
49 resolves_to: [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]
50 }"#,
45 &symbols, 51 &symbols,
46 ); 52 );
47 53
@@ -54,9 +60,12 @@ fn test_resolve_module() {
54 ", 60 ",
55 ); 61 );
56 62
57 let symbols = analysis.approximately_resolve_symbol(pos).unwrap(); 63 let symbols = analysis.approximately_resolve_symbol(pos).unwrap().unwrap();
58 assert_eq_dbg( 64 assert_eq_dbg(
59 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, 65 r#"ReferenceResolution {
66 reference_range: [4; 7),
67 resolves_to: [(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]
68 }"#,
60 &symbols, 69 &symbols,
61 ); 70 );
62} 71}
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs
index 8f11d5364..a2aa02149 100644
--- a/crates/ra_editor/src/extend_selection.rs
+++ b/crates/ra_editor/src/extend_selection.rs
@@ -48,13 +48,18 @@ fn extend_single_word_in_comment(leaf: SyntaxNodeRef, offset: TextUnit) -> Optio
48 let cursor_position: u32 = (offset - leaf.range().start()).into(); 48 let cursor_position: u32 = (offset - leaf.range().start()).into();
49 49
50 let (before, after) = text.split_at(cursor_position as usize); 50 let (before, after) = text.split_at(cursor_position as usize);
51 let start_idx = before.rfind(char::is_whitespace)? as u32; 51 let start_idx = before.rfind(char::is_whitespace).unwrap_or(0) as u32;
52 let end_idx = after.find(char::is_whitespace)? as u32; 52 let end_idx = after.find(char::is_whitespace).unwrap_or(after.len()) as u32;
53 53
54 let from: TextUnit = (start_idx + 1).into(); 54 let from: TextUnit = (start_idx + 1).into();
55 let to: TextUnit = (cursor_position + end_idx).into(); 55 let to: TextUnit = (cursor_position + end_idx).into();
56 56
57 Some(TextRange::from_to(from, to) + leaf.range().start()) 57 let range = TextRange::from_to(from, to);
58 if range.is_empty() {
59 None
60 } else {
61 Some(range + leaf.range().start())
62 }
58} 63}
59 64
60fn extend_ws(root: SyntaxNodeRef, ws: SyntaxNodeRef, offset: TextUnit) -> TextRange { 65fn extend_ws(root: SyntaxNodeRef, ws: SyntaxNodeRef, offset: TextUnit) -> TextRange {
@@ -179,7 +184,21 @@ fn bar(){}
179 184
180// fn foo(){} 185// fn foo(){}
181 "#, 186 "#,
182 &["// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"], 187 &["1", "// 1 + 1", "// fn foo() {\n// 1 + 1\n// }"],
188 );
189
190 do_check(
191 r#"
192// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
193// pub enum Direction {
194// <|> Next,
195// Prev
196// }
197"#,
198 &[
199 "// Next,",
200 "// #[derive(Debug, Clone, Copy, PartialEq, Eq)]\n// pub enum Direction {\n// Next,\n// Prev\n// }",
201 ],
183 ); 202 );
184 } 203 }
185 204
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs
index 6d3b0514a..9e25decfb 100644
--- a/crates/ra_editor/src/symbols.rs
+++ b/crates/ra_editor/src/symbols.rs
@@ -50,6 +50,61 @@ impl FileSymbol {
50 }) 50 })
51 .nth(0) 51 .nth(0)
52 } 52 }
53 /// Get a description of this node.
54 ///
55 /// e.g. `struct Name`, `enum Name`, `fn Name`
56 pub fn description(&self, file: &SourceFileNode) -> Option<String> {
57 // TODO: After type inference is done, add type information to improve the output
58 file.syntax()
59 .descendants()
60 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
61 .filter_map(|node: SyntaxNodeRef| {
62 // TODO: Refactor to be have less repetition
63 visitor()
64 .visit(|node: ast::FnDef| {
65 let mut string = "fn ".to_string();
66 node.name()?.syntax().text().push_to(&mut string);
67 Some(string)
68 })
69 .visit(|node: ast::StructDef| {
70 let mut string = "struct ".to_string();
71 node.name()?.syntax().text().push_to(&mut string);
72 Some(string)
73 })
74 .visit(|node: ast::EnumDef| {
75 let mut string = "enum ".to_string();
76 node.name()?.syntax().text().push_to(&mut string);
77 Some(string)
78 })
79 .visit(|node: ast::TraitDef| {
80 let mut string = "trait ".to_string();
81 node.name()?.syntax().text().push_to(&mut string);
82 Some(string)
83 })
84 .visit(|node: ast::Module| {
85 let mut string = "mod ".to_string();
86 node.name()?.syntax().text().push_to(&mut string);
87 Some(string)
88 })
89 .visit(|node: ast::TypeDef| {
90 let mut string = "type ".to_string();
91 node.name()?.syntax().text().push_to(&mut string);
92 Some(string)
93 })
94 .visit(|node: ast::ConstDef| {
95 let mut string = "const ".to_string();
96 node.name()?.syntax().text().push_to(&mut string);
97 Some(string)
98 })
99 .visit(|node: ast::StaticDef| {
100 let mut string = "static ".to_string();
101 node.name()?.syntax().text().push_to(&mut string);
102 Some(string)
103 })
104 .accept(node)?
105 })
106 .nth(0)
107 }
53} 108}
54 109
55pub fn file_symbols(file: &SourceFileNode) -> Vec<FileSymbol> { 110pub fn file_symbols(file: &SourceFileNode) -> Vec<FileSymbol> {
diff --git a/crates/ra_hir/src/function/mod.rs b/crates/ra_hir/src/function.rs
index 5187dc051..5187dc051 100644
--- a/crates/ra_hir/src/function/mod.rs
+++ b/crates/ra_hir/src/function.rs
diff --git a/crates/ra_hir/src/module/mod.rs b/crates/ra_hir/src/module.rs
index 580c737c3..580c737c3 100644
--- a/crates/ra_hir/src/module/mod.rs
+++ b/crates/ra_hir/src/module.rs
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
index 0eec38797..9f144e139 100644
--- a/crates/ra_hir/src/module/imp.rs
+++ b/crates/ra_hir/src/module/imp.rs
@@ -164,26 +164,26 @@ fn resolve_submodule(
164 164
165 let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); 165 let file_mod = RelativePathBuf::from(format!("../{}.rs", name));
166 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); 166 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name));
167 let points_to: Vec<FileId>; 167 let file_dir_mod = RelativePathBuf::from(format!("../{}/{}.rs", mod_name, name));
168 let problem: Option<Problem>; 168 let tmp1;
169 if is_dir_owner { 169 let tmp2;
170 points_to = [&file_mod, &dir_mod] 170 let candidates = if is_dir_owner {
171 .iter() 171 tmp1 = [&file_mod, &dir_mod];
172 .filter_map(|path| file_resolver.resolve(file_id, path)) 172 tmp1.iter()
173 .collect();
174 problem = if points_to.is_empty() {
175 Some(Problem::UnresolvedModule {
176 candidate: file_mod,
177 })
178 } else {
179 None
180 }
181 } else { 173 } else {
182 points_to = Vec::new(); 174 tmp2 = [&file_dir_mod];
183 problem = Some(Problem::NotDirOwner { 175 tmp2.iter()
184 move_to: RelativePathBuf::from(format!("../{}/mod.rs", mod_name)), 176 };
185 candidate: file_mod, 177
186 }); 178 let points_to = candidates
187 } 179 .filter_map(|path| file_resolver.resolve(file_id, path))
180 .collect::<Vec<_>>();
181 let problem = if points_to.is_empty() {
182 Some(Problem::UnresolvedModule {
183 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
184 })
185 } else {
186 None
187 };
188 (points_to, problem) 188 (points_to, problem)
189} 189}
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop.rs
index 0e1878906..0e1878906 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index af21254e4..92e92f836 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -203,8 +203,12 @@ pub fn handle_goto_definition(
203 params: req::TextDocumentPositionParams, 203 params: req::TextDocumentPositionParams,
204) -> Result<Option<req::GotoDefinitionResponse>> { 204) -> Result<Option<req::GotoDefinitionResponse>> {
205 let position = params.try_conv_with(&world)?; 205 let position = params.try_conv_with(&world)?;
206 let rr = match world.analysis().approximately_resolve_symbol(position)? {
207 None => return Ok(None),
208 Some(it) => it,
209 };
206 let mut res = Vec::new(); 210 let mut res = Vec::new();
207 for (file_id, symbol) in world.analysis().approximately_resolve_symbol(position)? { 211 for (file_id, symbol) in rr.resolves_to {
208 let line_index = world.analysis().file_line_index(file_id); 212 let line_index = world.analysis().file_line_index(file_id);
209 let location = to_location(file_id, symbol.node_range, &world, &line_index)?; 213 let location = to_location(file_id, symbol.node_range, &world, &line_index)?;
210 res.push(location) 214 res.push(location)
@@ -504,26 +508,30 @@ pub fn handle_hover(
504 world: ServerWorld, 508 world: ServerWorld,
505 params: req::TextDocumentPositionParams, 509 params: req::TextDocumentPositionParams,
506) -> Result<Option<Hover>> { 510) -> Result<Option<Hover>> {
511 // TODO: Cut down on number of allocations
507 let position = params.try_conv_with(&world)?; 512 let position = params.try_conv_with(&world)?;
508 let line_index = world.analysis().file_line_index(position.file_id); 513 let line_index = world.analysis().file_line_index(position.file_id);
509 514 let rr = match world.analysis().approximately_resolve_symbol(position)? {
510 for (file_id, symbol) in world.analysis().approximately_resolve_symbol(position)? { 515 None => return Ok(None),
511 let range = symbol.node_range.conv_with(&line_index); 516 Some(it) => it,
512 let comment = world.analysis.doc_comment_for(file_id, symbol)?; 517 };
513 518 let mut result = Vec::new();
514 if comment.is_some() { 519 for (file_id, symbol) in rr.resolves_to {
515 let contents = HoverContents::Scalar(MarkedString::String(comment.unwrap())); 520 if let Some(docs) = world.analysis().doc_text_for(file_id, symbol)? {
516 521 result.push(docs);
517 return Ok(Some(Hover {
518 contents,
519 range: Some(range),
520 }));
521 } 522 }
522 } 523 }
523 524 let range = rr.reference_range.conv_with(&line_index);
525 if result.len() > 0 {
526 return Ok(Some(Hover {
527 contents: HoverContents::Scalar(MarkedString::String(result.join("\n\n---\n"))),
528 range: Some(range),
529 }));
530 }
524 Ok(None) 531 Ok(None)
525} 532}
526 533
534/// Test doc comment
527pub fn handle_prepare_rename( 535pub fn handle_prepare_rename(
528 world: ServerWorld, 536 world: ServerWorld,
529 params: req::TextDocumentPositionParams, 537 params: req::TextDocumentPositionParams,
diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo.rs
index 4b3548ea9..4b3548ea9 100644
--- a/crates/ra_syntax/src/algo/mod.rs
+++ b/crates/ra_syntax/src/algo.rs
diff --git a/crates/ra_syntax/src/ast/mod.rs b/crates/ra_syntax/src/ast.rs
index 91c67119f..91c67119f 100644
--- a/crates/ra_syntax/src/ast/mod.rs
+++ b/crates/ra_syntax/src/ast.rs
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 53cd2118f..eed67637e 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -25,9 +25,9 @@ Grammar(
25 ["^", "CARET"], 25 ["^", "CARET"],
26 ["%", "PERCENT"], 26 ["%", "PERCENT"],
27 ], 27 ],
28 // TODO: Confirm surmision: the tokens which cannot be recorded in a single UTF-8 byte 28 // Tokens for which the longest match must be chosen (e.g. `..` is a DOTDOT, but `.` is a DOT)
29 multi_byte_tokens: [ 29 multi_byte_tokens: [
30 [".", "DOT"], // Note: DOT is here because <TODO: REASON> 30 [".", "DOT"],
31 ["..", "DOTDOT"], 31 ["..", "DOTDOT"],
32 ["...", "DOTDOTDOT"], 32 ["...", "DOTDOTDOT"],
33 ["..=", "DOTDOTEQ"], 33 ["..=", "DOTDOTEQ"],
diff --git a/crates/ra_syntax/src/grammar/mod.rs b/crates/ra_syntax/src/grammar.rs
index 06a37d648..06a37d648 100644
--- a/crates/ra_syntax/src/grammar/mod.rs
+++ b/crates/ra_syntax/src/grammar.rs
diff --git a/crates/ra_syntax/src/grammar/expressions/mod.rs b/crates/ra_syntax/src/grammar/expressions.rs
index 60c8602f9..60c8602f9 100644
--- a/crates/ra_syntax/src/grammar/expressions/mod.rs
+++ b/crates/ra_syntax/src/grammar/expressions.rs
diff --git a/crates/ra_syntax/src/grammar/items/mod.rs b/crates/ra_syntax/src/grammar/items.rs
index 4473c2fab..4473c2fab 100644
--- a/crates/ra_syntax/src/grammar/items/mod.rs
+++ b/crates/ra_syntax/src/grammar/items.rs
diff --git a/crates/ra_syntax/src/lexer/mod.rs b/crates/ra_syntax/src/lexer.rs
index f388da273..f388da273 100644
--- a/crates/ra_syntax/src/lexer/mod.rs
+++ b/crates/ra_syntax/src/lexer.rs
diff --git a/crates/ra_syntax/src/parser_impl/mod.rs b/crates/ra_syntax/src/parser_impl.rs
index cb6e370ac..cb6e370ac 100644
--- a/crates/ra_syntax/src/parser_impl/mod.rs
+++ b/crates/ra_syntax/src/parser_impl.rs
diff --git a/crates/ra_syntax/src/string_lexing/mod.rs b/crates/ra_syntax/src/string_lexing.rs
index 94853331f..94853331f 100644
--- a/crates/ra_syntax/src/string_lexing/mod.rs
+++ b/crates/ra_syntax/src/string_lexing.rs
diff --git a/crates/ra_syntax/src/syntax_kinds/mod.rs b/crates/ra_syntax/src/syntax_kinds.rs
index d53886676..d53886676 100644
--- a/crates/ra_syntax/src/syntax_kinds/mod.rs
+++ b/crates/ra_syntax/src/syntax_kinds.rs
diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs b/crates/ra_syntax/src/syntax_kinds/generated.rs
index c43a8bf65..3a869ad34 100644
--- a/crates/ra_syntax/src/syntax_kinds/generated.rs
+++ b/crates/ra_syntax/src/syntax_kinds/generated.rs
@@ -560,4 +560,3 @@ impl SyntaxKind {
560 Some(tok) 560 Some(tok)
561 } 561 }
562} 562}
563
diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs.tera b/crates/ra_syntax/src/syntax_kinds/generated.rs.tera
index c37e57702..21f9444b1 100644
--- a/crates/ra_syntax/src/syntax_kinds/generated.rs.tera
+++ b/crates/ra_syntax/src/syntax_kinds/generated.rs.tera
@@ -75,4 +75,3 @@ impl SyntaxKind {
75 Some(tok) 75 Some(tok)
76 } 76 }
77} 77}
78
diff --git a/crates/ra_syntax/src/validation/mod.rs b/crates/ra_syntax/src/validation.rs
index bdee8120c..bdee8120c 100644
--- a/crates/ra_syntax/src/validation/mod.rs
+++ b/crates/ra_syntax/src/validation.rs
diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow.rs
index cacd89dc8..cacd89dc8 100644
--- a/crates/ra_syntax/src/yellow/mod.rs
+++ b/crates/ra_syntax/src/yellow.rs
diff --git a/crates/tools/src/main.rs b/crates/tools/src/main.rs
index e312df537..36a7c83e2 100644
--- a/crates/tools/src/main.rs
+++ b/crates/tools/src/main.rs
@@ -79,15 +79,21 @@ fn tests_from_dir(dir: &Path) -> Result<HashMap<String, Test>> {
79 if entry.path().extension().unwrap_or_default() != "rs" { 79 if entry.path().extension().unwrap_or_default() != "rs" {
80 continue; 80 continue;
81 } 81 }
82 let text = fs::read_to_string(entry.path())?; 82 process_file(&mut res, entry.path())?;
83 }
84 let grammar_rs = dir.parent().unwrap().join("grammar.rs");
85 process_file(&mut res, &grammar_rs)?;
86 return Ok(res);
87 fn process_file(res: &mut HashMap<String, Test>, path: &Path) -> Result<()> {
88 let text = fs::read_to_string(path)?;
83 89
84 for (_, test) in collect_tests(&text) { 90 for (_, test) in collect_tests(&text) {
85 if let Some(old_test) = res.insert(test.name.clone(), test) { 91 if let Some(old_test) = res.insert(test.name.clone(), test) {
86 bail!("Duplicate test: {}", old_test.name) 92 bail!("Duplicate test: {}", old_test.name)
87 } 93 }
88 } 94 }
95 Ok(())
89 } 96 }
90 Ok(res)
91} 97}
92 98
93fn existing_tests(dir: &Path) -> Result<HashMap<String, (PathBuf, Test)>> { 99fn existing_tests(dir: &Path) -> Result<HashMap<String, (PathBuf, Test)>> {