aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock38
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs120
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs83
-rw-r--r--crates/assists/src/utils/insert_use.rs96
-rw-r--r--crates/hir_ty/Cargo.toml1
-rw-r--r--crates/hir_ty/src/tests.rs7
-rw-r--r--crates/rust-analyzer/src/config.rs9
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt27
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt9
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt36
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt9
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt9
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt18
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt18
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt18
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt18
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt27
-rw-r--r--crates/stdx/src/lib.rs30
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast.rs19
-rw-r--r--crates/syntax/src/ast/token_ext.rs51
-rw-r--r--crates/syntax/src/parsing/text_tree_sink.rs27
-rw-r--r--crates/syntax/test_data/parser/ok/0037_mod.rast6
23 files changed, 513 insertions, 165 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1a4a63550..494011068 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -139,9 +139,9 @@ dependencies = [
139 139
140[[package]] 140[[package]]
141name = "cc" 141name = "cc"
142version = "1.0.61" 142version = "1.0.62"
143source = "registry+https://github.com/rust-lang/crates.io-index" 143source = "registry+https://github.com/rust-lang/crates.io-index"
144checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" 144checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
145 145
146[[package]] 146[[package]]
147name = "cfg" 147name = "cfg"
@@ -398,11 +398,11 @@ dependencies = [
398 398
399[[package]] 399[[package]]
400name = "filetime" 400name = "filetime"
401version = "0.2.12" 401version = "0.2.13"
402source = "registry+https://github.com/rust-lang/crates.io-index" 402source = "registry+https://github.com/rust-lang/crates.io-index"
403checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" 403checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe"
404dependencies = [ 404dependencies = [
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]]
442name = "form_urlencoded"
443version = "1.0.0"
444source = "registry+https://github.com/rust-lang/crates.io-index"
445checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00"
446dependencies = [
447 "matches",
448 "percent-encoding",
449]
450
451[[package]]
442name = "fsevent" 452name = "fsevent"
443version = "2.0.2" 453version = "2.0.2"
444source = "registry+https://github.com/rust-lang/crates.io-index" 454source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -612,6 +622,7 @@ dependencies = [
612 "hir_expand", 622 "hir_expand",
613 "itertools", 623 "itertools",
614 "log", 624 "log",
625 "once_cell",
615 "profile", 626 "profile",
616 "rustc-hash", 627 "rustc-hash",
617 "scoped-tls", 628 "scoped-tls",
@@ -714,9 +725,9 @@ dependencies = [
714 725
715[[package]] 726[[package]]
716name = "inotify-sys" 727name = "inotify-sys"
717version = "0.1.3" 728version = "0.1.4"
718source = "registry+https://github.com/rust-lang/crates.io-index" 729source = "registry+https://github.com/rust-lang/crates.io-index"
719checksum = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" 730checksum = "c4563555856585ab3180a5bf0b2f9f8d301a728462afffc8195b3f5394229c55"
720dependencies = [ 731dependencies = [
721 "libc", 732 "libc",
722] 733]
@@ -1053,9 +1064,9 @@ checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
1053 1064
1054[[package]] 1065[[package]]
1055name = "once_cell" 1066name = "once_cell"
1056version = "1.4.1" 1067version = "1.5.1"
1057source = "registry+https://github.com/rust-lang/crates.io-index" 1068source = "registry+https://github.com/rust-lang/crates.io-index"
1058checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" 1069checksum = "f53cef67919d7d247eb9a2f128ca9e522789967ef1eb4ccd8c71a95a8aedf596"
1059 1070
1060[[package]] 1071[[package]]
1061name = "oorandom" 1072name = "oorandom"
@@ -1383,9 +1394,9 @@ dependencies = [
1383 1394
1384[[package]] 1395[[package]]
1385name = "rustc-ap-rustc_lexer" 1396name = "rustc-ap-rustc_lexer"
1386version = "686.0.0" 1397version = "688.0.0"
1387source = "registry+https://github.com/rust-lang/crates.io-index" 1398source = "registry+https://github.com/rust-lang/crates.io-index"
1388checksum = "a5b04cd2159495584d976d501c5394498470c2e94e4f0cebb8186562d407a678" 1399checksum = "ebbdcc99bd015349093fcbae4780fda21416fec5d8843acfb3d1733e130cd4db"
1389dependencies = [ 1400dependencies = [
1390 "unicode-xid", 1401 "unicode-xid",
1391] 1402]
@@ -1888,10 +1899,11 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
1888 1899
1889[[package]] 1900[[package]]
1890name = "url" 1901name = "url"
1891version = "2.1.1" 1902version = "2.2.0"
1892source = "registry+https://github.com/rust-lang/crates.io-index" 1903source = "registry+https://github.com/rust-lang/crates.io-index"
1893checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" 1904checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e"
1894dependencies = [ 1905dependencies = [
1906 "form_urlencoded",
1895 "idna", 1907 "idna",
1896 "matches", 1908 "matches",
1897 "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};
5use ide_db::{defs::Definition, search::Reference, RootDatabase}; 5use ide_db::{defs::Definition, search::Reference, RootDatabase};
6use rustc_hash::{FxHashMap, FxHashSet}; 6use rustc_hash::{FxHashMap, FxHashSet};
7use syntax::{ 7use 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
14use crate::{ 13use crate::{
@@ -130,17 +129,21 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En
130fn insert_import( 129fn 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
322mod my_mod { 329mod 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#"
360enum E {
361 <|>V { i: i32, j: i32 }
362}
363
364fn f() {
365 let e = E::V { i: 9, j: 2 };
366}
367"#,
368 r#"
369struct V{ pub i: i32, pub j: i32 }
370
371enum E {
372 V(V)
373}
374
375fn 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 {
372mod foo; 406mod foo;
373 407
374//- /foo.rs 408//- /foo.rs
375use V; 409use crate::{E, V};
376
377use crate::E;
378fn f() { 410fn 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
404struct V{ pub i: i32, pub j: i32 } 436struct V{ pub i: i32, pub j: i32 }
405 437
406enum E { 438enum E {
@@ -408,10 +440,42 @@ enum E {
408} 440}
409mod foo; 441mod foo;
410 442
443//- /foo.rs
444use crate::{E, V};
445fn 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#"
457enum A { <|>One { a: u32, b: u32 } }
458
459struct B(A);
460
461fn foo() {
462 let _ = B(A::One { a: 1, b: 2 });
463}
464"#,
465 r#"
466struct One{ pub a: u32, pub b: u32 }
467
468enum A { One(One) }
469
470struct B(A);
471
472fn 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#"
126mod bar { pub fn foo(x: i32, <|>y: i32) { x; } }
127fn b() { bar::foo(9, 2) }
128"#,
129 r#"
130mod bar { pub fn foo(x: i32) { x; } }
131fn 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#"
141pub fn foo<T>(x: T, <|>y: i32) { x; }
142fn b() { foo::<i32>(9, 2) }
143"#,
144 r#"
145pub fn foo<T>(x: T) { x; }
146fn 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#"
156pub fn foo<T>(x: i32, <|>y: T) { x; }
157fn b() { foo::<i32>(9, 2) }
158fn b2() { foo(9, 2) }
159"#,
160 r#"
161pub fn foo<T>(x: i32) { x; }
162fn b() { foo::<i32>(9) }
163fn 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
186fn foo(x: i32, <|>y: i32) { x; }
187
188mod foo;
189
190//- /foo.rs
191use super::foo;
192
193fn bar() {
194 let _ = foo(1, 2);
195}
196"#,
197 r#"
198//- /main.rs
199fn foo(x: i32) { x; }
200
201mod foo;
202
203//- /foo.rs
204use super::foo;
205
206fn 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};
14use test_utils::mark; 14use 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
81fn is_inner_attribute(node: SyntaxNode) -> bool {
82 ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
83}
84
85fn 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.
88pub(crate) fn insert_use<'a>( 91pub(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]
833fn main() {}", 837fn main() {}",
834 r"#![allow(unused_imports)] 838 r"#![allow(unused_imports)]
835 839
836use foo::bar; 840#![no_std]
837 841
842use foo::bar;
838fn main() {}", 843fn 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
854use 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. */
865fn 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
870use foo::bar::Baz;
871fn 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
886fn 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
895use foo::bar::Baz;
896fn main() {}"#,
839 ) 897 )
840 } 898 }
841 899
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index fdc65a5c3..cf5c38a23 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -35,3 +35,4 @@ expect-test = "1.0"
35tracing = "0.1" 35tracing = "0.1"
36tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } 36tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
37tracing-tree = { version = "0.1.4" } 37tracing-tree = { version = "0.1.4" }
38once_cell = { version = "1.5.0", features = ["unstable"] }
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 104ef334c..0a400cb70 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -22,7 +22,8 @@ use hir_def::{
22 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 22 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
23}; 23};
24use hir_expand::{db::AstDatabase, InFile}; 24use hir_expand::{db::AstDatabase, InFile};
25use stdx::{format_to, RacyFlag}; 25use once_cell::race::OnceBool;
26use stdx::format_to;
26use syntax::{ 27use syntax::{
27 algo, 28 algo,
28 ast::{self, AstNode}, 29 ast::{self, AstNode},
@@ -40,8 +41,8 @@ use crate::{
40// `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. 41// `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots.
41 42
42fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { 43fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> {
43 static ENABLE: RacyFlag = RacyFlag::new(); 44 static ENABLE: OnceBool = OnceBool::new();
44 if !ENABLE.get(|| env::var("CHALK_DEBUG").is_ok()) { 45 if !ENABLE.get_or_init(|| env::var("CHALK_DEBUG").is_ok()) {
45 return None; 46 return None;
46 } 47 }
47 48
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 372180ab5..74a021dbf 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -398,10 +398,13 @@ impl Config {
398 } 398 }
399 399
400 if let Some(code_action) = &doc_caps.code_action { 400 if let Some(code_action) = &doc_caps.code_action {
401 if let Some(resolve_support) = &code_action.resolve_support { 401 match (code_action.data_support, &code_action.resolve_support) {
402 if resolve_support.properties.iter().any(|it| it == "edit") { 402 (Some(true), Some(resolve_support)) => {
403 self.client_caps.code_action_resolve = true; 403 if resolve_support.properties.iter().any(|it| it == "edit") {
404 self.client_caps.code_action_resolve = true;
405 }
404 } 406 }
407 _ => (),
405 } 408 }
406 } 409 }
407 } 410 }
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/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 59d89f47d..374ed5910 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,8 +1,5 @@
1//! Missing batteries for standard libraries. 1//! Missing batteries for standard libraries.
2use std::{ 2use std::time::Instant;
3 sync::atomic::{AtomicUsize, Ordering},
4 time::Instant,
5};
6 3
7mod macros; 4mod macros;
8pub mod panic_context; 5pub mod panic_context;
@@ -150,31 +147,6 @@ where
150 left 147 left
151} 148}
152 149
153pub struct RacyFlag(AtomicUsize);
154
155impl RacyFlag {
156 pub const fn new() -> RacyFlag {
157 RacyFlag(AtomicUsize::new(!0))
158 }
159
160 pub fn get(&self, init: impl FnMut() -> bool) -> bool {
161 let mut init = Some(init);
162 self.get_impl(&mut || init.take().map_or(false, |mut f| f()))
163 }
164
165 fn get_impl(&self, init: &mut dyn FnMut() -> bool) -> bool {
166 match self.0.load(Ordering::Relaxed) {
167 0 => false,
168 1 => true,
169 _ => {
170 let res = init();
171 self.0.store(if res { 1 } else { 0 }, Ordering::Relaxed);
172 res
173 }
174 }
175 }
176}
177
178#[cfg(test)] 150#[cfg(test)]
179mod tests { 151mod tests {
180 use super::*; 152 use super::*;
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]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "686.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "688.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_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]
118fn test_doc_comment_of_items() { 118fn 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]
133fn 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]
133fn test_doc_comment_of_statics() { 148fn 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
15impl ast::Comment { 15impl 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
58const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { 57impl 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
71fn 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
83impl ast::Whitespace { 78impl 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;
5use parser::{ParseError, TreeSink}; 5use parser::{ParseError, TreeSink};
6 6
7use crate::{ 7use 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"