diff options
24 files changed, 731 insertions, 197 deletions
diff --git a/Cargo.lock b/Cargo.lock index c5645b2d2..494011068 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -139,9 +139,9 @@ dependencies = [ | |||
139 | 139 | ||
140 | [[package]] | 140 | [[package]] |
141 | name = "cc" | 141 | name = "cc" |
142 | version = "1.0.61" | 142 | version = "1.0.62" |
143 | source = "registry+https://github.com/rust-lang/crates.io-index" | 143 | source = "registry+https://github.com/rust-lang/crates.io-index" |
144 | checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" | 144 | checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" |
145 | 145 | ||
146 | [[package]] | 146 | [[package]] |
147 | name = "cfg" | 147 | name = "cfg" |
@@ -398,11 +398,11 @@ dependencies = [ | |||
398 | 398 | ||
399 | [[package]] | 399 | [[package]] |
400 | name = "filetime" | 400 | name = "filetime" |
401 | version = "0.2.12" | 401 | version = "0.2.13" |
402 | source = "registry+https://github.com/rust-lang/crates.io-index" | 402 | source = "registry+https://github.com/rust-lang/crates.io-index" |
403 | checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" | 403 | checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" |
404 | dependencies = [ | 404 | dependencies = [ |
405 | "cfg-if 0.1.10", | 405 | "cfg-if 1.0.0", |
406 | "libc", | 406 | "libc", |
407 | "redox_syscall", | 407 | "redox_syscall", |
408 | "winapi 0.3.9", | 408 | "winapi 0.3.9", |
@@ -439,6 +439,16 @@ dependencies = [ | |||
439 | ] | 439 | ] |
440 | 440 | ||
441 | [[package]] | 441 | [[package]] |
442 | name = "form_urlencoded" | ||
443 | version = "1.0.0" | ||
444 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
445 | checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" | ||
446 | dependencies = [ | ||
447 | "matches", | ||
448 | "percent-encoding", | ||
449 | ] | ||
450 | |||
451 | [[package]] | ||
442 | name = "fsevent" | 452 | name = "fsevent" |
443 | version = "2.0.2" | 453 | version = "2.0.2" |
444 | source = "registry+https://github.com/rust-lang/crates.io-index" | 454 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -715,9 +725,9 @@ dependencies = [ | |||
715 | 725 | ||
716 | [[package]] | 726 | [[package]] |
717 | name = "inotify-sys" | 727 | name = "inotify-sys" |
718 | version = "0.1.3" | 728 | version = "0.1.4" |
719 | source = "registry+https://github.com/rust-lang/crates.io-index" | 729 | source = "registry+https://github.com/rust-lang/crates.io-index" |
720 | checksum = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" | 730 | checksum = "c4563555856585ab3180a5bf0b2f9f8d301a728462afffc8195b3f5394229c55" |
721 | dependencies = [ | 731 | dependencies = [ |
722 | "libc", | 732 | "libc", |
723 | ] | 733 | ] |
@@ -1384,9 +1394,9 @@ dependencies = [ | |||
1384 | 1394 | ||
1385 | [[package]] | 1395 | [[package]] |
1386 | name = "rustc-ap-rustc_lexer" | 1396 | name = "rustc-ap-rustc_lexer" |
1387 | version = "686.0.0" | 1397 | version = "688.0.0" |
1388 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1389 | checksum = "a5b04cd2159495584d976d501c5394498470c2e94e4f0cebb8186562d407a678" | 1399 | checksum = "ebbdcc99bd015349093fcbae4780fda21416fec5d8843acfb3d1733e130cd4db" |
1390 | dependencies = [ | 1400 | dependencies = [ |
1391 | "unicode-xid", | 1401 | "unicode-xid", |
1392 | ] | 1402 | ] |
@@ -1889,10 +1899,11 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" | |||
1889 | 1899 | ||
1890 | [[package]] | 1900 | [[package]] |
1891 | name = "url" | 1901 | name = "url" |
1892 | version = "2.1.1" | 1902 | version = "2.2.0" |
1893 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1894 | checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" | 1904 | checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" |
1895 | dependencies = [ | 1905 | dependencies = [ |
1906 | "form_urlencoded", | ||
1896 | "idna", | 1907 | "idna", |
1897 | "matches", | 1908 | "matches", |
1898 | "percent-encoding", | 1909 | "percent-encoding", |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 84662d832..067afabf2 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -5,10 +5,9 @@ use hir::{AsName, EnumVariant, Module, ModuleDef, Name}; | |||
5 | use ide_db::{defs::Definition, search::Reference, RootDatabase}; | 5 | use ide_db::{defs::Definition, search::Reference, RootDatabase}; |
6 | use rustc_hash::{FxHashMap, FxHashSet}; | 6 | use rustc_hash::{FxHashMap, FxHashSet}; |
7 | use syntax::{ | 7 | use syntax::{ |
8 | algo::find_node_at_offset, | 8 | algo::{find_node_at_offset, SyntaxRewriter}, |
9 | algo::SyntaxRewriter, | 9 | ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, |
10 | ast::{self, edit::IndentLevel, make, ArgListOwner, AstNode, NameOwner, VisibilityOwner}, | 10 | SourceFile, SyntaxElement, SyntaxNode, T, |
11 | SourceFile, SyntaxElement, | ||
12 | }; | 11 | }; |
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
@@ -130,17 +129,21 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En | |||
130 | fn insert_import( | 129 | fn insert_import( |
131 | ctx: &AssistContext, | 130 | ctx: &AssistContext, |
132 | rewriter: &mut SyntaxRewriter, | 131 | rewriter: &mut SyntaxRewriter, |
133 | path: &ast::PathExpr, | 132 | scope_node: &SyntaxNode, |
134 | module: &Module, | 133 | module: &Module, |
135 | enum_module_def: &ModuleDef, | 134 | enum_module_def: &ModuleDef, |
136 | variant_hir_name: &Name, | 135 | variant_hir_name: &Name, |
137 | ) -> Option<()> { | 136 | ) -> Option<()> { |
138 | let db = ctx.db(); | 137 | let db = ctx.db(); |
139 | let mod_path = module.find_use_path(db, enum_module_def.clone()); | 138 | let mod_path = module.find_use_path_prefixed( |
139 | db, | ||
140 | enum_module_def.clone(), | ||
141 | ctx.config.insert_use.prefix_kind, | ||
142 | ); | ||
140 | if let Some(mut mod_path) = mod_path { | 143 | if let Some(mut mod_path) = mod_path { |
141 | mod_path.segments.pop(); | 144 | mod_path.segments.pop(); |
142 | mod_path.segments.push(variant_hir_name.clone()); | 145 | mod_path.segments.push(variant_hir_name.clone()); |
143 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; | 146 | let scope = ImportScope::find_insert_use_container(scope_node, ctx)?; |
144 | 147 | ||
145 | *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); | 148 | *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); |
146 | } | 149 | } |
@@ -204,27 +207,31 @@ fn update_reference( | |||
204 | variant_hir_name: &Name, | 207 | variant_hir_name: &Name, |
205 | visited_modules_set: &mut FxHashSet<Module>, | 208 | visited_modules_set: &mut FxHashSet<Module>, |
206 | ) -> Option<()> { | 209 | ) -> Option<()> { |
207 | let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>( | 210 | let offset = reference.file_range.range.start(); |
208 | source_file.syntax(), | 211 | let (segment, expr) = if let Some(path_expr) = |
209 | reference.file_range.range.start(), | 212 | find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset) |
210 | )?; | 213 | { |
211 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; | 214 | // tuple variant |
212 | let list = call.arg_list()?; | 215 | (path_expr.path()?.segment()?, path_expr.syntax().parent()?.clone()) |
213 | let segment = path_expr.path()?.segment()?; | 216 | } else if let Some(record_expr) = |
214 | let module = ctx.sema.scope(&path_expr.syntax()).module()?; | 217 | find_node_at_offset::<ast::RecordExpr>(source_file.syntax(), offset) |
218 | { | ||
219 | // record variant | ||
220 | (record_expr.path()?.segment()?, record_expr.syntax().clone()) | ||
221 | } else { | ||
222 | return None; | ||
223 | }; | ||
224 | |||
225 | let module = ctx.sema.scope(&expr).module()?; | ||
215 | if !visited_modules_set.contains(&module) { | 226 | if !visited_modules_set.contains(&module) { |
216 | if insert_import(ctx, rewriter, &path_expr, &module, enum_module_def, variant_hir_name) | 227 | if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some() |
217 | .is_some() | ||
218 | { | 228 | { |
219 | visited_modules_set.insert(module); | 229 | visited_modules_set.insert(module); |
220 | } | 230 | } |
221 | } | 231 | } |
222 | 232 | rewriter.insert_after(segment.syntax(), &make::token(T!['('])); | |
223 | let lparen = syntax::SyntaxElement::from(list.l_paren_token()?); | 233 | rewriter.insert_after(segment.syntax(), segment.syntax()); |
224 | let rparen = syntax::SyntaxElement::from(list.r_paren_token()?); | 234 | rewriter.insert_after(&expr, &make::token(T![')'])); |
225 | rewriter.insert_after(&lparen, segment.syntax()); | ||
226 | rewriter.insert_after(&lparen, &lparen); | ||
227 | rewriter.insert_before(&rparen, &rparen); | ||
228 | Some(()) | 235 | Some(()) |
229 | } | 236 | } |
230 | 237 | ||
@@ -320,7 +327,7 @@ fn another_fn() { | |||
320 | r#"use my_mod::my_other_mod::MyField; | 327 | r#"use my_mod::my_other_mod::MyField; |
321 | 328 | ||
322 | mod my_mod { | 329 | mod my_mod { |
323 | use my_other_mod::MyField; | 330 | use self::my_other_mod::MyField; |
324 | 331 | ||
325 | fn another_fn() { | 332 | fn another_fn() { |
326 | let m = my_other_mod::MyEnum::MyField(MyField(1, 1)); | 333 | let m = my_other_mod::MyEnum::MyField(MyField(1, 1)); |
@@ -346,6 +353,33 @@ fn another_fn() { | |||
346 | } | 353 | } |
347 | 354 | ||
348 | #[test] | 355 | #[test] |
356 | fn extract_record_fix_references() { | ||
357 | check_assist( | ||
358 | extract_struct_from_enum_variant, | ||
359 | r#" | ||
360 | enum E { | ||
361 | <|>V { i: i32, j: i32 } | ||
362 | } | ||
363 | |||
364 | fn f() { | ||
365 | let e = E::V { i: 9, j: 2 }; | ||
366 | } | ||
367 | "#, | ||
368 | r#" | ||
369 | struct V{ pub i: i32, pub j: i32 } | ||
370 | |||
371 | enum E { | ||
372 | V(V) | ||
373 | } | ||
374 | |||
375 | fn f() { | ||
376 | let e = E::V(V { i: 9, j: 2 }); | ||
377 | } | ||
378 | "#, | ||
379 | ) | ||
380 | } | ||
381 | |||
382 | #[test] | ||
349 | fn test_several_files() { | 383 | fn test_several_files() { |
350 | check_assist( | 384 | check_assist( |
351 | extract_struct_from_enum_variant, | 385 | extract_struct_from_enum_variant, |
@@ -372,9 +406,7 @@ enum E { | |||
372 | mod foo; | 406 | mod foo; |
373 | 407 | ||
374 | //- /foo.rs | 408 | //- /foo.rs |
375 | use V; | 409 | use crate::{E, V}; |
376 | |||
377 | use crate::E; | ||
378 | fn f() { | 410 | fn f() { |
379 | let e = E::V(V(9, 2)); | 411 | let e = E::V(V(9, 2)); |
380 | } | 412 | } |
@@ -384,7 +416,6 @@ fn f() { | |||
384 | 416 | ||
385 | #[test] | 417 | #[test] |
386 | fn test_several_files_record() { | 418 | fn test_several_files_record() { |
387 | // FIXME: this should fix the usage as well! | ||
388 | check_assist( | 419 | check_assist( |
389 | extract_struct_from_enum_variant, | 420 | extract_struct_from_enum_variant, |
390 | r#" | 421 | r#" |
@@ -401,6 +432,7 @@ fn f() { | |||
401 | } | 432 | } |
402 | "#, | 433 | "#, |
403 | r#" | 434 | r#" |
435 | //- /main.rs | ||
404 | struct V{ pub i: i32, pub j: i32 } | 436 | struct V{ pub i: i32, pub j: i32 } |
405 | 437 | ||
406 | enum E { | 438 | enum E { |
@@ -408,10 +440,42 @@ enum E { | |||
408 | } | 440 | } |
409 | mod foo; | 441 | mod foo; |
410 | 442 | ||
443 | //- /foo.rs | ||
444 | use crate::{E, V}; | ||
445 | fn f() { | ||
446 | let e = E::V(V { i: 9, j: 2 }); | ||
447 | } | ||
411 | "#, | 448 | "#, |
412 | ) | 449 | ) |
413 | } | 450 | } |
414 | 451 | ||
452 | #[test] | ||
453 | fn test_extract_struct_record_nested_call_exp() { | ||
454 | check_assist( | ||
455 | extract_struct_from_enum_variant, | ||
456 | r#" | ||
457 | enum A { <|>One { a: u32, b: u32 } } | ||
458 | |||
459 | struct B(A); | ||
460 | |||
461 | fn foo() { | ||
462 | let _ = B(A::One { a: 1, b: 2 }); | ||
463 | } | ||
464 | "#, | ||
465 | r#" | ||
466 | struct One{ pub a: u32, pub b: u32 } | ||
467 | |||
468 | enum A { One(One) } | ||
469 | |||
470 | struct B(A); | ||
471 | |||
472 | fn foo() { | ||
473 | let _ = B(A::One(One { a: 1, b: 2 })); | ||
474 | } | ||
475 | "#, | ||
476 | ); | ||
477 | } | ||
478 | |||
415 | fn check_not_applicable(ra_fixture: &str) { | 479 | fn check_not_applicable(ra_fixture: &str) { |
416 | let fixture = | 480 | let fixture = |
417 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | 481 | format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); |
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs index 5fccca54b..1ff5e92b0 100644 --- a/crates/assists/src/handlers/remove_unused_param.rs +++ b/crates/assists/src/handlers/remove_unused_param.rs | |||
@@ -73,7 +73,8 @@ fn process_usage( | |||
73 | let source_file = ctx.sema.parse(usage.file_range.file_id); | 73 | let source_file = ctx.sema.parse(usage.file_range.file_id); |
74 | let call_expr: ast::CallExpr = | 74 | let call_expr: ast::CallExpr = |
75 | find_node_at_range(source_file.syntax(), usage.file_range.range)?; | 75 | find_node_at_range(source_file.syntax(), usage.file_range.range)?; |
76 | if call_expr.expr()?.syntax().text_range() != usage.file_range.range { | 76 | let call_expr_range = call_expr.expr()?.syntax().text_range(); |
77 | if !call_expr_range.contains_range(usage.file_range.range) { | ||
77 | return None; | 78 | return None; |
78 | } | 79 | } |
79 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; | 80 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; |
@@ -118,6 +119,53 @@ fn b() { foo(9, ) } | |||
118 | } | 119 | } |
119 | 120 | ||
120 | #[test] | 121 | #[test] |
122 | fn remove_unused_qualified_call() { | ||
123 | check_assist( | ||
124 | remove_unused_param, | ||
125 | r#" | ||
126 | mod bar { pub fn foo(x: i32, <|>y: i32) { x; } } | ||
127 | fn b() { bar::foo(9, 2) } | ||
128 | "#, | ||
129 | r#" | ||
130 | mod bar { pub fn foo(x: i32) { x; } } | ||
131 | fn b() { bar::foo(9) } | ||
132 | "#, | ||
133 | ); | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn remove_unused_turbofished_func() { | ||
138 | check_assist( | ||
139 | remove_unused_param, | ||
140 | r#" | ||
141 | pub fn foo<T>(x: T, <|>y: i32) { x; } | ||
142 | fn b() { foo::<i32>(9, 2) } | ||
143 | "#, | ||
144 | r#" | ||
145 | pub fn foo<T>(x: T) { x; } | ||
146 | fn b() { foo::<i32>(9) } | ||
147 | "#, | ||
148 | ); | ||
149 | } | ||
150 | |||
151 | #[test] | ||
152 | fn remove_unused_generic_unused_param_func() { | ||
153 | check_assist( | ||
154 | remove_unused_param, | ||
155 | r#" | ||
156 | pub fn foo<T>(x: i32, <|>y: T) { x; } | ||
157 | fn b() { foo::<i32>(9, 2) } | ||
158 | fn b2() { foo(9, 2) } | ||
159 | "#, | ||
160 | r#" | ||
161 | pub fn foo<T>(x: i32) { x; } | ||
162 | fn b() { foo::<i32>(9) } | ||
163 | fn b2() { foo(9) } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
121 | fn keep_used() { | 169 | fn keep_used() { |
122 | mark::check!(keep_used); | 170 | mark::check!(keep_used); |
123 | check_assist_not_applicable( | 171 | check_assist_not_applicable( |
@@ -128,4 +176,37 @@ fn main() { foo(9, 2) } | |||
128 | "#, | 176 | "#, |
129 | ); | 177 | ); |
130 | } | 178 | } |
179 | |||
180 | #[test] | ||
181 | fn remove_across_files() { | ||
182 | check_assist( | ||
183 | remove_unused_param, | ||
184 | r#" | ||
185 | //- /main.rs | ||
186 | fn foo(x: i32, <|>y: i32) { x; } | ||
187 | |||
188 | mod foo; | ||
189 | |||
190 | //- /foo.rs | ||
191 | use super::foo; | ||
192 | |||
193 | fn bar() { | ||
194 | let _ = foo(1, 2); | ||
195 | } | ||
196 | "#, | ||
197 | r#" | ||
198 | //- /main.rs | ||
199 | fn foo(x: i32) { x; } | ||
200 | |||
201 | mod foo; | ||
202 | |||
203 | //- /foo.rs | ||
204 | use super::foo; | ||
205 | |||
206 | fn bar() { | ||
207 | let _ = foo(1); | ||
208 | } | ||
209 | "#, | ||
210 | ) | ||
211 | } | ||
131 | } | 212 | } |
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index 84a0dffdd..af3fc96b6 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -9,7 +9,7 @@ use syntax::{ | |||
9 | edit::{AstNodeEdit, IndentLevel}, | 9 | edit::{AstNodeEdit, IndentLevel}, |
10 | make, AstNode, PathSegmentKind, VisibilityOwner, | 10 | make, AstNode, PathSegmentKind, VisibilityOwner, |
11 | }, | 11 | }, |
12 | InsertPosition, SyntaxElement, SyntaxNode, | 12 | AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, |
13 | }; | 13 | }; |
14 | use test_utils::mark; | 14 | use test_utils::mark; |
15 | 15 | ||
@@ -63,27 +63,30 @@ impl ImportScope { | |||
63 | } | 63 | } |
64 | } | 64 | } |
65 | 65 | ||
66 | fn insert_pos_after_inner_attribute(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { | 66 | fn insert_pos_after_last_inner_element(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { |
67 | // check if the scope has inner attributes, we dont want to insert in front of them | 67 | self.as_syntax_node() |
68 | match self | 68 | .children_with_tokens() |
69 | .as_syntax_node() | 69 | .filter(|child| match child { |
70 | .children() | 70 | NodeOrToken::Node(node) => is_inner_attribute(node.clone()), |
71 | // no flat_map here cause we want to short circuit the iterator | 71 | NodeOrToken::Token(token) => is_inner_comment(token.clone()), |
72 | .map(ast::Attr::cast) | ||
73 | .take_while(|attr| { | ||
74 | attr.as_ref().map(|attr| attr.kind() == ast::AttrKind::Inner).unwrap_or(false) | ||
75 | }) | 72 | }) |
76 | .last() | 73 | .last() |
77 | .flatten() | 74 | .map(|last_inner_element| { |
78 | { | 75 | (InsertPosition::After(last_inner_element.into()), AddBlankLine::BeforeTwice) |
79 | Some(attr) => { | 76 | }) |
80 | (InsertPosition::After(attr.syntax().clone().into()), AddBlankLine::BeforeTwice) | 77 | .unwrap_or_else(|| self.first_insert_pos()) |
81 | } | ||
82 | None => self.first_insert_pos(), | ||
83 | } | ||
84 | } | 78 | } |
85 | } | 79 | } |
86 | 80 | ||
81 | fn is_inner_attribute(node: SyntaxNode) -> bool { | ||
82 | ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner) | ||
83 | } | ||
84 | |||
85 | fn is_inner_comment(token: SyntaxToken) -> bool { | ||
86 | ast::Comment::cast(token).and_then(|comment| comment.kind().doc) | ||
87 | == Some(ast::CommentPlacement::Inner) | ||
88 | } | ||
89 | |||
87 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 90 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
88 | pub(crate) fn insert_use<'a>( | 91 | pub(crate) fn insert_use<'a>( |
89 | scope: &ImportScope, | 92 | scope: &ImportScope, |
@@ -558,7 +561,7 @@ fn find_insert_position( | |||
558 | (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) | 561 | (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) |
559 | } | 562 | } |
560 | // there are no imports in this file at all | 563 | // there are no imports in this file at all |
561 | None => scope.insert_pos_after_inner_attribute(), | 564 | None => scope.insert_pos_after_last_inner_element(), |
562 | }, | 565 | }, |
563 | } | 566 | } |
564 | } | 567 | } |
@@ -830,12 +833,67 @@ use foo::bar;", | |||
830 | "foo::bar", | 833 | "foo::bar", |
831 | r"#![allow(unused_imports)] | 834 | r"#![allow(unused_imports)] |
832 | 835 | ||
836 | #![no_std] | ||
833 | fn main() {}", | 837 | fn main() {}", |
834 | r"#![allow(unused_imports)] | 838 | r"#![allow(unused_imports)] |
835 | 839 | ||
836 | use foo::bar; | 840 | #![no_std] |
837 | 841 | ||
842 | use foo::bar; | ||
838 | fn main() {}", | 843 | fn main() {}", |
844 | ); | ||
845 | } | ||
846 | |||
847 | #[test] | ||
848 | fn inserts_after_single_line_inner_comments() { | ||
849 | check_none( | ||
850 | "foo::bar::Baz", | ||
851 | "//! Single line inner comments do not allow any code before them.", | ||
852 | r#"//! Single line inner comments do not allow any code before them. | ||
853 | |||
854 | use foo::bar::Baz;"#, | ||
855 | ); | ||
856 | } | ||
857 | |||
858 | #[test] | ||
859 | fn inserts_after_multiline_inner_comments() { | ||
860 | check_none( | ||
861 | "foo::bar::Baz", | ||
862 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
863 | |||
864 | /*! Still an inner comment, cannot place any code before. */ | ||
865 | fn main() {}"#, | ||
866 | r#"/*! Multiline inner comments do not allow any code before them. */ | ||
867 | |||
868 | /*! Still an inner comment, cannot place any code before. */ | ||
869 | |||
870 | use foo::bar::Baz; | ||
871 | fn main() {}"#, | ||
872 | ) | ||
873 | } | ||
874 | |||
875 | #[test] | ||
876 | fn inserts_after_all_inner_items() { | ||
877 | check_none( | ||
878 | "foo::bar::Baz", | ||
879 | r#"#![allow(unused_imports)] | ||
880 | /*! Multiline line comment 2 */ | ||
881 | |||
882 | |||
883 | //! Single line comment 1 | ||
884 | #![no_std] | ||
885 | //! Single line comment 2 | ||
886 | fn main() {}"#, | ||
887 | r#"#![allow(unused_imports)] | ||
888 | /*! Multiline line comment 2 */ | ||
889 | |||
890 | |||
891 | //! Single line comment 1 | ||
892 | #![no_std] | ||
893 | //! Single line comment 2 | ||
894 | |||
895 | use foo::bar::Baz; | ||
896 | fn main() {}"#, | ||
839 | ) | 897 | ) |
840 | } | 898 | } |
841 | 899 | ||
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs index d5f6a4025..608a031d4 100644 --- a/crates/project_model/src/cargo_workspace.rs +++ b/crates/project_model/src/cargo_workspace.rs | |||
@@ -64,6 +64,9 @@ pub struct CargoConfig { | |||
64 | 64 | ||
65 | /// rustc target | 65 | /// rustc target |
66 | pub target: Option<String>, | 66 | pub target: Option<String>, |
67 | |||
68 | /// rustc private crate source | ||
69 | pub rustc_source: Option<AbsPathBuf>, | ||
67 | } | 70 | } |
68 | 71 | ||
69 | pub type Package = Idx<PackageData>; | 72 | pub type Package = Idx<PackageData>; |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index e92cfea59..4531b1928 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -9,6 +9,7 @@ use std::{ | |||
9 | fmt, | 9 | fmt, |
10 | fs::{self, read_dir, ReadDir}, | 10 | fs::{self, read_dir, ReadDir}, |
11 | io, | 11 | io, |
12 | path::Component, | ||
12 | process::Command, | 13 | process::Command, |
13 | }; | 14 | }; |
14 | 15 | ||
@@ -31,7 +32,7 @@ pub use proc_macro_api::ProcMacroClient; | |||
31 | #[derive(Clone, Eq, PartialEq)] | 32 | #[derive(Clone, Eq, PartialEq)] |
32 | pub enum ProjectWorkspace { | 33 | pub enum ProjectWorkspace { |
33 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. | 34 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
34 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, | 35 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot, rustc: Option<CargoWorkspace> }, |
35 | /// Project workspace was manually specified using a `rust-project.json` file. | 36 | /// Project workspace was manually specified using a `rust-project.json` file. |
36 | Json { project: ProjectJson, sysroot: Option<Sysroot> }, | 37 | Json { project: ProjectJson, sysroot: Option<Sysroot> }, |
37 | } | 38 | } |
@@ -39,10 +40,14 @@ pub enum ProjectWorkspace { | |||
39 | impl fmt::Debug for ProjectWorkspace { | 40 | impl fmt::Debug for ProjectWorkspace { |
40 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 41 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
41 | match self { | 42 | match self { |
42 | ProjectWorkspace::Cargo { cargo, sysroot } => f | 43 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => f |
43 | .debug_struct("Cargo") | 44 | .debug_struct("Cargo") |
44 | .field("n_packages", &cargo.packages().len()) | 45 | .field("n_packages", &cargo.packages().len()) |
45 | .field("n_sysroot_crates", &sysroot.crates().len()) | 46 | .field("n_sysroot_crates", &sysroot.crates().len()) |
47 | .field( | ||
48 | "n_rustc_compiler_crates", | ||
49 | &rustc.as_ref().map_or(0, |rc| rc.packages().len()), | ||
50 | ) | ||
46 | .finish(), | 51 | .finish(), |
47 | ProjectWorkspace::Json { project, sysroot } => { | 52 | ProjectWorkspace::Json { project, sysroot } => { |
48 | let mut debug_struct = f.debug_struct("Json"); | 53 | let mut debug_struct = f.debug_struct("Json"); |
@@ -200,7 +205,19 @@ impl ProjectWorkspace { | |||
200 | } else { | 205 | } else { |
201 | Sysroot::default() | 206 | Sysroot::default() |
202 | }; | 207 | }; |
203 | ProjectWorkspace::Cargo { cargo, sysroot } | 208 | |
209 | let rustc = if let Some(rustc_dir) = &cargo_config.rustc_source { | ||
210 | Some( | ||
211 | CargoWorkspace::from_cargo_metadata(&rustc_dir, cargo_config) | ||
212 | .with_context(|| { | ||
213 | format!("Failed to read Cargo metadata for Rust sources") | ||
214 | })?, | ||
215 | ) | ||
216 | } else { | ||
217 | None | ||
218 | }; | ||
219 | |||
220 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } | ||
204 | } | 221 | } |
205 | }; | 222 | }; |
206 | 223 | ||
@@ -238,31 +255,43 @@ impl ProjectWorkspace { | |||
238 | }) | 255 | }) |
239 | })) | 256 | })) |
240 | .collect::<Vec<_>>(), | 257 | .collect::<Vec<_>>(), |
241 | ProjectWorkspace::Cargo { cargo, sysroot } => cargo | 258 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { |
242 | .packages() | 259 | let roots = cargo |
243 | .map(|pkg| { | 260 | .packages() |
244 | let is_member = cargo[pkg].is_member; | 261 | .map(|pkg| { |
245 | let pkg_root = cargo[pkg].root().to_path_buf(); | 262 | let is_member = cargo[pkg].is_member; |
246 | 263 | let pkg_root = cargo[pkg].root().to_path_buf(); | |
247 | let mut include = vec![pkg_root.clone()]; | 264 | |
248 | include.extend(cargo[pkg].out_dir.clone()); | 265 | let mut include = vec![pkg_root.clone()]; |
249 | 266 | include.extend(cargo[pkg].out_dir.clone()); | |
250 | let mut exclude = vec![pkg_root.join(".git")]; | 267 | |
251 | if is_member { | 268 | let mut exclude = vec![pkg_root.join(".git")]; |
252 | exclude.push(pkg_root.join("target")); | 269 | if is_member { |
253 | } else { | 270 | exclude.push(pkg_root.join("target")); |
254 | exclude.push(pkg_root.join("tests")); | 271 | } else { |
255 | exclude.push(pkg_root.join("examples")); | 272 | exclude.push(pkg_root.join("tests")); |
256 | exclude.push(pkg_root.join("benches")); | 273 | exclude.push(pkg_root.join("examples")); |
257 | } | 274 | exclude.push(pkg_root.join("benches")); |
258 | PackageRoot { is_member, include, exclude } | 275 | } |
259 | }) | 276 | PackageRoot { is_member, include, exclude } |
260 | .chain(sysroot.crates().map(|krate| PackageRoot { | 277 | }) |
261 | is_member: false, | 278 | .chain(sysroot.crates().map(|krate| PackageRoot { |
262 | include: vec![sysroot[krate].root_dir().to_path_buf()], | 279 | is_member: false, |
263 | exclude: Vec::new(), | 280 | include: vec![sysroot[krate].root_dir().to_path_buf()], |
264 | })) | 281 | exclude: Vec::new(), |
265 | .collect(), | 282 | })); |
283 | if let Some(rustc_packages) = rustc { | ||
284 | roots | ||
285 | .chain(rustc_packages.packages().map(|krate| PackageRoot { | ||
286 | is_member: false, | ||
287 | include: vec![rustc_packages[krate].root().to_path_buf()], | ||
288 | exclude: Vec::new(), | ||
289 | })) | ||
290 | .collect() | ||
291 | } else { | ||
292 | roots.collect() | ||
293 | } | ||
294 | } | ||
266 | } | 295 | } |
267 | } | 296 | } |
268 | 297 | ||
@@ -273,7 +302,7 @@ impl ProjectWorkspace { | |||
273 | .filter_map(|(_, krate)| krate.proc_macro_dylib_path.as_ref()) | 302 | .filter_map(|(_, krate)| krate.proc_macro_dylib_path.as_ref()) |
274 | .cloned() | 303 | .cloned() |
275 | .collect(), | 304 | .collect(), |
276 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo | 305 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot, rustc: _rustc_crates } => cargo |
277 | .packages() | 306 | .packages() |
278 | .filter_map(|pkg| cargo[pkg].proc_macro_dylib_path.as_ref()) | 307 | .filter_map(|pkg| cargo[pkg].proc_macro_dylib_path.as_ref()) |
279 | .cloned() | 308 | .cloned() |
@@ -284,8 +313,9 @@ impl ProjectWorkspace { | |||
284 | pub fn n_packages(&self) -> usize { | 313 | pub fn n_packages(&self) -> usize { |
285 | match self { | 314 | match self { |
286 | ProjectWorkspace::Json { project, .. } => project.n_crates(), | 315 | ProjectWorkspace::Json { project, .. } => project.n_crates(), |
287 | ProjectWorkspace::Cargo { cargo, sysroot } => { | 316 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { |
288 | cargo.packages().len() + sysroot.crates().len() | 317 | let rustc_package_len = rustc.as_ref().map_or(0, |rc| rc.packages().len()); |
318 | cargo.packages().len() + sysroot.crates().len() + rustc_package_len | ||
289 | } | 319 | } |
290 | } | 320 | } |
291 | } | 321 | } |
@@ -365,7 +395,7 @@ impl ProjectWorkspace { | |||
365 | } | 395 | } |
366 | } | 396 | } |
367 | } | 397 | } |
368 | ProjectWorkspace::Cargo { cargo, sysroot } => { | 398 | ProjectWorkspace::Cargo { cargo, sysroot, rustc } => { |
369 | let (public_deps, libproc_macro) = | 399 | let (public_deps, libproc_macro) = |
370 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); | 400 | sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load); |
371 | 401 | ||
@@ -373,50 +403,25 @@ impl ProjectWorkspace { | |||
373 | cfg_options.extend(get_rustc_cfg_options(target)); | 403 | cfg_options.extend(get_rustc_cfg_options(target)); |
374 | 404 | ||
375 | let mut pkg_to_lib_crate = FxHashMap::default(); | 405 | let mut pkg_to_lib_crate = FxHashMap::default(); |
376 | let mut pkg_crates = FxHashMap::default(); | ||
377 | 406 | ||
378 | // Add test cfg for non-sysroot crates | 407 | // Add test cfg for non-sysroot crates |
379 | cfg_options.insert_atom("test".into()); | 408 | cfg_options.insert_atom("test".into()); |
380 | cfg_options.insert_atom("debug_assertions".into()); | 409 | cfg_options.insert_atom("debug_assertions".into()); |
381 | 410 | ||
411 | let mut pkg_crates = FxHashMap::default(); | ||
412 | |||
382 | // Next, create crates for each package, target pair | 413 | // Next, create crates for each package, target pair |
383 | for pkg in cargo.packages() { | 414 | for pkg in cargo.packages() { |
384 | let mut lib_tgt = None; | 415 | let mut lib_tgt = None; |
385 | for &tgt in cargo[pkg].targets.iter() { | 416 | for &tgt in cargo[pkg].targets.iter() { |
386 | let root = cargo[tgt].root.as_path(); | 417 | if let Some(crate_id) = add_target_crate_root( |
387 | if let Some(file_id) = load(root) { | 418 | &mut crate_graph, |
388 | let edition = cargo[pkg].edition; | 419 | &cargo[pkg], |
389 | let cfg_options = { | 420 | &cargo[tgt], |
390 | let mut opts = cfg_options.clone(); | 421 | &cfg_options, |
391 | for feature in cargo[pkg].features.iter() { | 422 | proc_macro_client, |
392 | opts.insert_key_value("feature".into(), feature.into()); | 423 | load, |
393 | } | 424 | ) { |
394 | opts.extend(cargo[pkg].cfgs.iter().cloned()); | ||
395 | opts | ||
396 | }; | ||
397 | let mut env = Env::default(); | ||
398 | if let Some(out_dir) = &cargo[pkg].out_dir { | ||
399 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | ||
400 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
401 | env.set("OUT_DIR", out_dir); | ||
402 | } | ||
403 | } | ||
404 | let proc_macro = cargo[pkg] | ||
405 | .proc_macro_dylib_path | ||
406 | .as_ref() | ||
407 | .map(|it| proc_macro_client.by_dylib_path(&it)) | ||
408 | .unwrap_or_default(); | ||
409 | |||
410 | let display_name = | ||
411 | CrateDisplayName::from_canonical_name(cargo[pkg].name.clone()); | ||
412 | let crate_id = crate_graph.add_crate_root( | ||
413 | file_id, | ||
414 | edition, | ||
415 | Some(display_name), | ||
416 | cfg_options, | ||
417 | env, | ||
418 | proc_macro.clone(), | ||
419 | ); | ||
420 | if cargo[tgt].kind == TargetKind::Lib { | 425 | if cargo[tgt].kind == TargetKind::Lib { |
421 | lib_tgt = Some((crate_id, cargo[tgt].name.clone())); | 426 | lib_tgt = Some((crate_id, cargo[tgt].name.clone())); |
422 | pkg_to_lib_crate.insert(pkg, crate_id); | 427 | pkg_to_lib_crate.insert(pkg, crate_id); |
@@ -484,6 +489,92 @@ impl ProjectWorkspace { | |||
484 | } | 489 | } |
485 | } | 490 | } |
486 | } | 491 | } |
492 | |||
493 | let mut rustc_pkg_crates = FxHashMap::default(); | ||
494 | |||
495 | // If the user provided a path to rustc sources, we add all the rustc_private crates | ||
496 | // and create dependencies on them for the crates in the current workspace | ||
497 | if let Some(rustc_workspace) = rustc { | ||
498 | for pkg in rustc_workspace.packages() { | ||
499 | for &tgt in rustc_workspace[pkg].targets.iter() { | ||
500 | if rustc_workspace[tgt].kind != TargetKind::Lib { | ||
501 | continue; | ||
502 | } | ||
503 | // Exclude alloc / core / std | ||
504 | if rustc_workspace[tgt] | ||
505 | .root | ||
506 | .components() | ||
507 | .any(|c| c == Component::Normal("library".as_ref())) | ||
508 | { | ||
509 | continue; | ||
510 | } | ||
511 | |||
512 | if let Some(crate_id) = add_target_crate_root( | ||
513 | &mut crate_graph, | ||
514 | &rustc_workspace[pkg], | ||
515 | &rustc_workspace[tgt], | ||
516 | &cfg_options, | ||
517 | proc_macro_client, | ||
518 | load, | ||
519 | ) { | ||
520 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
521 | // Add dependencies on the core / std / alloc for rustc | ||
522 | for (name, krate) in public_deps.iter() { | ||
523 | if let Err(_) = | ||
524 | crate_graph.add_dep(crate_id, name.clone(), *krate) | ||
525 | { | ||
526 | log::error!( | ||
527 | "cyclic dependency on {} for {}", | ||
528 | name, | ||
529 | &cargo[pkg].name | ||
530 | ) | ||
531 | } | ||
532 | } | ||
533 | rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | // Now add a dep edge from all targets of upstream to the lib | ||
538 | // target of downstream. | ||
539 | for pkg in rustc_workspace.packages() { | ||
540 | for dep in rustc_workspace[pkg].dependencies.iter() { | ||
541 | let name = CrateName::new(&dep.name).unwrap(); | ||
542 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
543 | for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { | ||
544 | if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { | ||
545 | log::error!( | ||
546 | "cyclic dependency {} -> {}", | ||
547 | &rustc_workspace[pkg].name, | ||
548 | &rustc_workspace[dep.pkg].name | ||
549 | ) | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | // Add dependencies for all the crates of the current workspace to rustc_private libraries | ||
557 | for dep in rustc_workspace.packages() { | ||
558 | let name = CrateName::normalize_dashes(&rustc_workspace[dep].name); | ||
559 | |||
560 | if let Some(&to) = pkg_to_lib_crate.get(&dep) { | ||
561 | for pkg in cargo.packages() { | ||
562 | if !cargo[pkg].is_member { | ||
563 | continue; | ||
564 | } | ||
565 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
566 | if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { | ||
567 | log::error!( | ||
568 | "cyclic dependency {} -> {}", | ||
569 | &cargo[pkg].name, | ||
570 | &rustc_workspace[dep].name | ||
571 | ) | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | } | ||
487 | } | 578 | } |
488 | } | 579 | } |
489 | if crate_graph.patch_cfg_if() { | 580 | if crate_graph.patch_cfg_if() { |
@@ -537,6 +628,52 @@ fn utf8_stdout(mut cmd: Command) -> Result<String> { | |||
537 | Ok(stdout.trim().to_string()) | 628 | Ok(stdout.trim().to_string()) |
538 | } | 629 | } |
539 | 630 | ||
631 | fn add_target_crate_root( | ||
632 | crate_graph: &mut CrateGraph, | ||
633 | pkg: &cargo_workspace::PackageData, | ||
634 | tgt: &cargo_workspace::TargetData, | ||
635 | cfg_options: &CfgOptions, | ||
636 | proc_macro_client: &ProcMacroClient, | ||
637 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, | ||
638 | ) -> Option<CrateId> { | ||
639 | let root = tgt.root.as_path(); | ||
640 | if let Some(file_id) = load(root) { | ||
641 | let edition = pkg.edition; | ||
642 | let cfg_options = { | ||
643 | let mut opts = cfg_options.clone(); | ||
644 | for feature in pkg.features.iter() { | ||
645 | opts.insert_key_value("feature".into(), feature.into()); | ||
646 | } | ||
647 | opts.extend(pkg.cfgs.iter().cloned()); | ||
648 | opts | ||
649 | }; | ||
650 | let mut env = Env::default(); | ||
651 | if let Some(out_dir) = &pkg.out_dir { | ||
652 | // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() | ||
653 | if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) { | ||
654 | env.set("OUT_DIR", out_dir); | ||
655 | } | ||
656 | } | ||
657 | let proc_macro = pkg | ||
658 | .proc_macro_dylib_path | ||
659 | .as_ref() | ||
660 | .map(|it| proc_macro_client.by_dylib_path(&it)) | ||
661 | .unwrap_or_default(); | ||
662 | |||
663 | let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); | ||
664 | let crate_id = crate_graph.add_crate_root( | ||
665 | file_id, | ||
666 | edition, | ||
667 | Some(display_name), | ||
668 | cfg_options, | ||
669 | env, | ||
670 | proc_macro.clone(), | ||
671 | ); | ||
672 | |||
673 | return Some(crate_id); | ||
674 | } | ||
675 | None | ||
676 | } | ||
540 | fn sysroot_to_crate_graph( | 677 | fn sysroot_to_crate_graph( |
541 | crate_graph: &mut CrateGraph, | 678 | crate_graph: &mut CrateGraph, |
542 | sysroot: &Sysroot, | 679 | sysroot: &Sysroot, |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9cc14fe82..372180ab5 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -7,7 +7,7 @@ | |||
7 | //! configure the server itself, feature flags are passed into analysis, and | 7 | //! configure the server itself, feature flags are passed into analysis, and |
8 | //! tweak things like automatic insertion of `()` in completions. | 8 | //! tweak things like automatic insertion of `()` in completions. |
9 | 9 | ||
10 | use std::{ffi::OsString, path::PathBuf}; | 10 | use std::{convert::TryFrom, ffi::OsString, path::PathBuf}; |
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use hir::PrefixKind; | 13 | use hir::PrefixKind; |
@@ -227,12 +227,25 @@ impl Config { | |||
227 | self.notifications = | 227 | self.notifications = |
228 | NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound }; | 228 | NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound }; |
229 | self.cargo_autoreload = data.cargo_autoreload; | 229 | self.cargo_autoreload = data.cargo_autoreload; |
230 | |||
231 | let rustc_source = if let Some(rustc_source) = data.rustcSource { | ||
232 | let rustpath: PathBuf = rustc_source.into(); | ||
233 | AbsPathBuf::try_from(rustpath) | ||
234 | .map_err(|_| { | ||
235 | log::error!("rustc source directory must be an absolute path"); | ||
236 | }) | ||
237 | .ok() | ||
238 | } else { | ||
239 | None | ||
240 | }; | ||
241 | |||
230 | self.cargo = CargoConfig { | 242 | self.cargo = CargoConfig { |
231 | no_default_features: data.cargo_noDefaultFeatures, | 243 | no_default_features: data.cargo_noDefaultFeatures, |
232 | all_features: data.cargo_allFeatures, | 244 | all_features: data.cargo_allFeatures, |
233 | features: data.cargo_features.clone(), | 245 | features: data.cargo_features.clone(), |
234 | load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck, | 246 | load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck, |
235 | target: data.cargo_target.clone(), | 247 | target: data.cargo_target.clone(), |
248 | rustc_source: rustc_source, | ||
236 | }; | 249 | }; |
237 | self.runnables = RunnablesConfig { | 250 | self.runnables = RunnablesConfig { |
238 | override_cargo: data.runnables_overrideCargo, | 251 | override_cargo: data.runnables_overrideCargo, |
@@ -532,5 +545,6 @@ config_data! { | |||
532 | rustfmt_overrideCommand: Option<Vec<String>> = None, | 545 | rustfmt_overrideCommand: Option<Vec<String>> = None, |
533 | 546 | ||
534 | withSysroot: bool = true, | 547 | withSysroot: bool = true, |
548 | rustcSource : Option<String> = None, | ||
535 | } | 549 | } |
536 | } | 550 | } |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt index 58d47d32a..5b2e5187a 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/compiler/mir/tagset.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/compiler/mir/tagset.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -29,7 +36,14 @@ | |||
29 | [ | 36 | [ |
30 | DiagnosticRelatedInformation { | 37 | DiagnosticRelatedInformation { |
31 | location: Location { | 38 | location: Location { |
32 | uri: "file:///test/compiler/lib.rs", | 39 | uri: Url { |
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/compiler/lib.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
33 | range: Range { | 47 | range: Range { |
34 | start: Position { | 48 | start: Position { |
35 | line: 0, | 49 | line: 0, |
@@ -45,7 +59,14 @@ | |||
45 | }, | 59 | }, |
46 | DiagnosticRelatedInformation { | 60 | DiagnosticRelatedInformation { |
47 | location: Location { | 61 | location: Location { |
48 | uri: "file:///test/compiler/mir/tagset.rs", | 62 | uri: Url { |
63 | scheme: "file", | ||
64 | host: None, | ||
65 | port: None, | ||
66 | path: "/test/compiler/mir/tagset.rs", | ||
67 | query: None, | ||
68 | fragment: None, | ||
69 | }, | ||
49 | range: Range { | 70 | range: Range { |
50 | start: Position { | 71 | start: Position { |
51 | line: 41, | 72 | line: 41, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt index 6aa26bf63..116f0ff73 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/src/main.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/src/main.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt index 7aaffaba2..bbec6a796 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/crates/hir_def/src/data.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/crates/hir_def/src/data.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -25,7 +32,14 @@ | |||
25 | [ | 32 | [ |
26 | DiagnosticRelatedInformation { | 33 | DiagnosticRelatedInformation { |
27 | location: Location { | 34 | location: Location { |
28 | uri: "file:///test/crates/hir_def/src/path.rs", | 35 | uri: Url { |
36 | scheme: "file", | ||
37 | host: None, | ||
38 | port: None, | ||
39 | path: "/test/crates/hir_def/src/path.rs", | ||
40 | query: None, | ||
41 | fragment: None, | ||
42 | }, | ||
29 | range: Range { | 43 | range: Range { |
30 | start: Position { | 44 | start: Position { |
31 | line: 264, | 45 | line: 264, |
@@ -47,7 +61,14 @@ | |||
47 | fixes: [], | 61 | fixes: [], |
48 | }, | 62 | }, |
49 | MappedRustDiagnostic { | 63 | MappedRustDiagnostic { |
50 | url: "file:///test/crates/hir_def/src/path.rs", | 64 | url: Url { |
65 | scheme: "file", | ||
66 | host: None, | ||
67 | port: None, | ||
68 | path: "/test/crates/hir_def/src/path.rs", | ||
69 | query: None, | ||
70 | fragment: None, | ||
71 | }, | ||
51 | diagnostic: Diagnostic { | 72 | diagnostic: Diagnostic { |
52 | range: Range { | 73 | range: Range { |
53 | start: Position { | 74 | start: Position { |
@@ -72,7 +93,14 @@ | |||
72 | [ | 93 | [ |
73 | DiagnosticRelatedInformation { | 94 | DiagnosticRelatedInformation { |
74 | location: Location { | 95 | location: Location { |
75 | uri: "file:///test/crates/hir_def/src/data.rs", | 96 | uri: Url { |
97 | scheme: "file", | ||
98 | host: None, | ||
99 | port: None, | ||
100 | path: "/test/crates/hir_def/src/data.rs", | ||
101 | query: None, | ||
102 | fragment: None, | ||
103 | }, | ||
76 | range: Range { | 104 | range: Range { |
77 | start: Position { | 105 | start: Position { |
78 | line: 79, | 106 | line: 79, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt index 584213420..2cbf657e5 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/compiler/ty/list_iter.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/compiler/ty/list_iter.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt index 2610e4e20..1142dc2ac 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/runtime/compiler_support.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/runtime/compiler_support.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt index a8d85f008..c709de95f 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/driver/subcommand/repl.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/driver/subcommand/repl.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -46,7 +53,14 @@ | |||
46 | SnippetWorkspaceEdit { | 53 | SnippetWorkspaceEdit { |
47 | changes: Some( | 54 | changes: Some( |
48 | { | 55 | { |
49 | "file:///test/driver/subcommand/repl.rs": [ | 56 | Url { |
57 | scheme: "file", | ||
58 | host: None, | ||
59 | port: None, | ||
60 | path: "/test/driver/subcommand/repl.rs", | ||
61 | query: None, | ||
62 | fragment: None, | ||
63 | }: [ | ||
50 | TextEdit { | 64 | TextEdit { |
51 | range: Range { | 65 | range: Range { |
52 | start: Position { | 66 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt index 0b8937376..632f438d7 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/driver/subcommand/repl.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/driver/subcommand/repl.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -46,7 +53,14 @@ | |||
46 | SnippetWorkspaceEdit { | 53 | SnippetWorkspaceEdit { |
47 | changes: Some( | 54 | changes: Some( |
48 | { | 55 | { |
49 | "file:///test/driver/subcommand/repl.rs": [ | 56 | Url { |
57 | scheme: "file", | ||
58 | host: None, | ||
59 | port: None, | ||
60 | path: "/test/driver/subcommand/repl.rs", | ||
61 | query: None, | ||
62 | fragment: None, | ||
63 | }: [ | ||
50 | TextEdit { | 64 | TextEdit { |
51 | range: Range { | 65 | range: Range { |
52 | start: Position { | 66 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt index 7fa9dee62..c0b79428d 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/driver/subcommand/repl.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/driver/subcommand/repl.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -46,7 +53,14 @@ | |||
46 | SnippetWorkspaceEdit { | 53 | SnippetWorkspaceEdit { |
47 | changes: Some( | 54 | changes: Some( |
48 | { | 55 | { |
49 | "file:///test/driver/subcommand/repl.rs": [ | 56 | Url { |
57 | scheme: "file", | ||
58 | host: None, | ||
59 | port: None, | ||
60 | path: "/test/driver/subcommand/repl.rs", | ||
61 | query: None, | ||
62 | fragment: None, | ||
63 | }: [ | ||
50 | TextEdit { | 64 | TextEdit { |
51 | range: Range { | 65 | range: Range { |
52 | start: Position { | 66 | start: Position { |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt index ba1b98b33..782c72dbd 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/compiler/ty/select.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/compiler/ty/select.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -29,7 +36,14 @@ | |||
29 | [ | 36 | [ |
30 | DiagnosticRelatedInformation { | 37 | DiagnosticRelatedInformation { |
31 | location: Location { | 38 | location: Location { |
32 | uri: "file:///test/compiler/ty/select.rs", | 39 | uri: Url { |
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/compiler/ty/select.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
33 | range: Range { | 47 | range: Range { |
34 | start: Position { | 48 | start: Position { |
35 | line: 218, | 49 | line: 218, |
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt index 3c97b2084..d3f27ab6a 100644 --- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt +++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt | |||
@@ -1,6 +1,13 @@ | |||
1 | [ | 1 | [ |
2 | MappedRustDiagnostic { | 2 | MappedRustDiagnostic { |
3 | url: "file:///test/src/main.rs", | 3 | url: Url { |
4 | scheme: "file", | ||
5 | host: None, | ||
6 | port: None, | ||
7 | path: "/test/src/main.rs", | ||
8 | query: None, | ||
9 | fragment: None, | ||
10 | }, | ||
4 | diagnostic: Diagnostic { | 11 | diagnostic: Diagnostic { |
5 | range: Range { | 12 | range: Range { |
6 | start: Position { | 13 | start: Position { |
@@ -29,7 +36,14 @@ | |||
29 | [ | 36 | [ |
30 | DiagnosticRelatedInformation { | 37 | DiagnosticRelatedInformation { |
31 | location: Location { | 38 | location: Location { |
32 | uri: "file:///test/src/main.rs", | 39 | uri: Url { |
40 | scheme: "file", | ||
41 | host: None, | ||
42 | port: None, | ||
43 | path: "/test/src/main.rs", | ||
44 | query: None, | ||
45 | fragment: None, | ||
46 | }, | ||
33 | range: Range { | 47 | range: Range { |
34 | start: Position { | 48 | start: Position { |
35 | line: 2, | 49 | line: 2, |
@@ -61,7 +75,14 @@ | |||
61 | SnippetWorkspaceEdit { | 75 | SnippetWorkspaceEdit { |
62 | changes: Some( | 76 | changes: Some( |
63 | { | 77 | { |
64 | "file:///test/src/main.rs": [ | 78 | Url { |
79 | scheme: "file", | ||
80 | host: None, | ||
81 | port: None, | ||
82 | path: "/test/src/main.rs", | ||
83 | query: None, | ||
84 | fragment: None, | ||
85 | }: [ | ||
65 | TextEdit { | 86 | TextEdit { |
66 | range: Range { | 87 | range: Range { |
67 | start: Position { | 88 | start: Position { |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 0eabd51bd..11c8d0e5f 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -246,7 +246,9 @@ impl GlobalState { | |||
246 | .iter() | 246 | .iter() |
247 | .enumerate() | 247 | .enumerate() |
248 | .filter_map(|(id, w)| match w { | 248 | .filter_map(|(id, w)| match w { |
249 | ProjectWorkspace::Cargo { cargo, sysroot: _ } => Some((id, cargo.workspace_root())), | 249 | ProjectWorkspace::Cargo { cargo, sysroot: _, rustc: _ } => { |
250 | Some((id, cargo.workspace_root())) | ||
251 | } | ||
250 | ProjectWorkspace::Json { project, .. } => { | 252 | ProjectWorkspace::Json { project, .. } => { |
251 | // Enable flychecks for json projects if a custom flycheck command was supplied | 253 | // Enable flychecks for json projects if a custom flycheck command was supplied |
252 | // in the workspace configuration. | 254 | // in the workspace configuration. |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 61d2acb49..1fe907753 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -13,7 +13,7 @@ doctest = false | |||
13 | [dependencies] | 13 | [dependencies] |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | rowan = "0.10.0" | 15 | rowan = "0.10.0" |
16 | rustc_lexer = { version = "686.0.0", package = "rustc-ap-rustc_lexer" } | 16 | rustc_lexer = { version = "688.0.0", package = "rustc-ap-rustc_lexer" } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | arrayvec = "0.5.1" | 18 | arrayvec = "0.5.1" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 8a0e3d27b..7844f9ed6 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs | |||
@@ -115,10 +115,10 @@ fn test_doc_comment_none() { | |||
115 | } | 115 | } |
116 | 116 | ||
117 | #[test] | 117 | #[test] |
118 | fn test_doc_comment_of_items() { | 118 | fn test_outer_doc_comment_of_items() { |
119 | let file = SourceFile::parse( | 119 | let file = SourceFile::parse( |
120 | r#" | 120 | r#" |
121 | //! doc | 121 | /// doc |
122 | // non-doc | 122 | // non-doc |
123 | mod foo {} | 123 | mod foo {} |
124 | "#, | 124 | "#, |
@@ -130,6 +130,21 @@ fn test_doc_comment_of_items() { | |||
130 | } | 130 | } |
131 | 131 | ||
132 | #[test] | 132 | #[test] |
133 | fn test_inner_doc_comment_of_items() { | ||
134 | let file = SourceFile::parse( | ||
135 | r#" | ||
136 | //! doc | ||
137 | // non-doc | ||
138 | mod foo {} | ||
139 | "#, | ||
140 | ) | ||
141 | .ok() | ||
142 | .unwrap(); | ||
143 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
144 | assert!(module.doc_comment_text().is_none()); | ||
145 | } | ||
146 | |||
147 | #[test] | ||
133 | fn test_doc_comment_of_statics() { | 148 | fn test_doc_comment_of_statics() { |
134 | let file = SourceFile::parse( | 149 | let file = SourceFile::parse( |
135 | r#" | 150 | r#" |
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index e4e512f2e..2661c753e 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs | |||
@@ -14,16 +14,15 @@ use crate::{ | |||
14 | 14 | ||
15 | impl ast::Comment { | 15 | impl ast::Comment { |
16 | pub fn kind(&self) -> CommentKind { | 16 | pub fn kind(&self) -> CommentKind { |
17 | kind_by_prefix(self.text()) | 17 | CommentKind::from_text(self.text()) |
18 | } | 18 | } |
19 | 19 | ||
20 | pub fn prefix(&self) -> &'static str { | 20 | pub fn prefix(&self) -> &'static str { |
21 | for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { | 21 | let &(prefix, _kind) = CommentKind::BY_PREFIX |
22 | if *k == self.kind() && self.text().starts_with(prefix) { | 22 | .iter() |
23 | return prefix; | 23 | .find(|&(prefix, kind)| self.kind() == *kind && self.text().starts_with(prefix)) |
24 | } | 24 | .unwrap(); |
25 | } | 25 | prefix |
26 | unreachable!() | ||
27 | } | 26 | } |
28 | } | 27 | } |
29 | 28 | ||
@@ -55,29 +54,25 @@ pub enum CommentPlacement { | |||
55 | Outer, | 54 | Outer, |
56 | } | 55 | } |
57 | 56 | ||
58 | const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { | 57 | impl CommentKind { |
59 | use {CommentPlacement::*, CommentShape::*}; | 58 | const BY_PREFIX: [(&'static str, CommentKind); 8] = [ |
60 | &[ | 59 | ("/**/", CommentKind { shape: CommentShape::Block, doc: None }), |
61 | ("////", CommentKind { shape: Line, doc: None }), | 60 | ("////", CommentKind { shape: CommentShape::Line, doc: None }), |
62 | ("///", CommentKind { shape: Line, doc: Some(Outer) }), | 61 | ("///", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Outer) }), |
63 | ("//!", CommentKind { shape: Line, doc: Some(Inner) }), | 62 | ("//!", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Inner) }), |
64 | ("/**", CommentKind { shape: Block, doc: Some(Outer) }), | 63 | ("/**", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Outer) }), |
65 | ("/*!", CommentKind { shape: Block, doc: Some(Inner) }), | 64 | ("/*!", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Inner) }), |
66 | ("//", CommentKind { shape: Line, doc: None }), | 65 | ("//", CommentKind { shape: CommentShape::Line, doc: None }), |
67 | ("/*", CommentKind { shape: Block, doc: None }), | 66 | ("/*", CommentKind { shape: CommentShape::Block, doc: None }), |
68 | ] | 67 | ]; |
69 | }; | ||
70 | 68 | ||
71 | fn kind_by_prefix(text: &str) -> CommentKind { | 69 | pub(crate) fn from_text(text: &str) -> CommentKind { |
72 | if text == "/**/" { | 70 | let &(_prefix, kind) = CommentKind::BY_PREFIX |
73 | return CommentKind { shape: CommentShape::Block, doc: None }; | 71 | .iter() |
74 | } | 72 | .find(|&(prefix, _kind)| text.starts_with(prefix)) |
75 | for (prefix, kind) in COMMENT_PREFIX_TO_KIND.iter() { | 73 | .unwrap(); |
76 | if text.starts_with(prefix) { | 74 | kind |
77 | return *kind; | ||
78 | } | ||
79 | } | 75 | } |
80 | panic!("bad comment text: {:?}", text) | ||
81 | } | 76 | } |
82 | 77 | ||
83 | impl ast::Whitespace { | 78 | impl ast::Whitespace { |
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs index c1b5f246d..997bc5d28 100644 --- a/crates/syntax/src/parsing/text_tree_sink.rs +++ b/crates/syntax/src/parsing/text_tree_sink.rs | |||
@@ -5,6 +5,7 @@ use std::mem; | |||
5 | use parser::{ParseError, TreeSink}; | 5 | use parser::{ParseError, TreeSink}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | ast, | ||
8 | parsing::Token, | 9 | parsing::Token, |
9 | syntax_node::GreenNode, | 10 | syntax_node::GreenNode, |
10 | SmolStr, SyntaxError, | 11 | SmolStr, SyntaxError, |
@@ -153,24 +154,22 @@ fn n_attached_trivias<'a>( | |||
153 | 154 | ||
154 | while let Some((i, (kind, text))) = trivias.next() { | 155 | while let Some((i, (kind, text))) = trivias.next() { |
155 | match kind { | 156 | match kind { |
156 | WHITESPACE => { | 157 | WHITESPACE if text.contains("\n\n") => { |
157 | if text.contains("\n\n") { | 158 | // we check whether the next token is a doc-comment |
158 | // we check whether the next token is a doc-comment | 159 | // and skip the whitespace in this case |
159 | // and skip the whitespace in this case | 160 | if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) { |
160 | if let Some((peek_kind, peek_text)) = | 161 | let comment_kind = ast::CommentKind::from_text(peek_text); |
161 | trivias.peek().map(|(_, pair)| pair) | 162 | if comment_kind.doc == Some(ast::CommentPlacement::Outer) { |
162 | { | 163 | continue; |
163 | if *peek_kind == COMMENT | ||
164 | && peek_text.starts_with("///") | ||
165 | && !peek_text.starts_with("////") | ||
166 | { | ||
167 | continue; | ||
168 | } | ||
169 | } | 164 | } |
170 | break; | ||
171 | } | 165 | } |
166 | break; | ||
172 | } | 167 | } |
173 | COMMENT => { | 168 | COMMENT => { |
169 | let comment_kind = ast::CommentKind::from_text(text); | ||
170 | if comment_kind.doc == Some(ast::CommentPlacement::Inner) { | ||
171 | break; | ||
172 | } | ||
174 | res = i + 1; | 173 | res = i + 1; |
175 | } | 174 | } |
176 | _ => (), | 175 | _ => (), |
diff --git a/crates/syntax/test_data/parser/ok/0037_mod.rast b/crates/syntax/test_data/parser/ok/0037_mod.rast index 1d5d94bde..35577272e 100644 --- a/crates/syntax/test_data/parser/ok/0037_mod.rast +++ b/crates/syntax/test_data/parser/ok/0037_mod.rast | |||
@@ -1,9 +1,9 @@ | |||
1 | [email protected] | 1 | [email protected] |
2 | [email protected] "// https://github.com ..." | 2 | [email protected] "// https://github.com ..." |
3 | [email protected] "\n\n" | 3 | [email protected] "\n\n" |
4 | MODULE@62..93 | 4 | COMMENT@62..70 "//! docs" |
5 | COMMENT@62..70 "//! docs" | 5 | WHITESPACE@70..71 "\n" |
6 | WHITESPACE@70..71 "\n" | 6 | MODULE@71..93 |
7 | [email protected] "// non-docs" | 7 | [email protected] "// non-docs" |
8 | [email protected] "\n" | 8 | [email protected] "\n" |
9 | [email protected] "mod" | 9 | [email protected] "mod" |
diff --git a/editors/code/package.json b/editors/code/package.json index b02c80773..3768679fe 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -692,6 +692,14 @@ | |||
692 | }, | 692 | }, |
693 | "default": [], | 693 | "default": [], |
694 | "description": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be '--release'" | 694 | "description": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be '--release'" |
695 | }, | ||
696 | "rust-analyzer.rustcSource": { | ||
697 | "type": [ | ||
698 | "null", | ||
699 | "string" | ||
700 | ], | ||
701 | "default": null, | ||
702 | "description": "Path to the rust compiler sources, for usage in rustc_private projects." | ||
695 | } | 703 | } |
696 | } | 704 | } |
697 | }, | 705 | }, |