diff options
Diffstat (limited to 'crates/ra_ide/src/diagnostics.rs')
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 91 |
1 files changed, 44 insertions, 47 deletions
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index bf14a467f..fd9abb55b 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -11,7 +11,7 @@ use hir::{ | |||
11 | Semantics, | 11 | Semantics, |
12 | }; | 12 | }; |
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use ra_db::{RelativePath, SourceDatabase, SourceDatabaseExt}; | 14 | use ra_db::SourceDatabase; |
15 | use ra_ide_db::RootDatabase; | 15 | use ra_ide_db::RootDatabase; |
16 | use ra_prof::profile; | 16 | use ra_prof::profile; |
17 | use ra_syntax::{ | 17 | use ra_syntax::{ |
@@ -57,14 +57,10 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
57 | }) | 57 | }) |
58 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 58 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
59 | let original_file = d.source().file_id.original_file(db); | 59 | let original_file = d.source().file_id.original_file(db); |
60 | let source_root = db.file_source_root(original_file); | 60 | let fix = Fix::new( |
61 | let path = db | 61 | "Create module", |
62 | .file_relative_path(original_file) | 62 | FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() }.into(), |
63 | .parent() | 63 | ); |
64 | .unwrap_or_else(|| RelativePath::new("")) | ||
65 | .join(&d.candidate); | ||
66 | let fix = | ||
67 | Fix::new("Create module", FileSystemEdit::CreateFile { source_root, path }.into()); | ||
68 | res.borrow_mut().push(Diagnostic { | 64 | res.borrow_mut().push(Diagnostic { |
69 | range: sema.diagnostics_range(d).range, | 65 | range: sema.diagnostics_range(d).range, |
70 | message: d.message(), | 66 | message: d.message(), |
@@ -187,7 +183,8 @@ fn check_struct_shorthand_initialization( | |||
187 | if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { | 183 | if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) { |
188 | let field_name = name_ref.syntax().text().to_string(); | 184 | let field_name = name_ref.syntax().text().to_string(); |
189 | let field_expr = expr.syntax().text().to_string(); | 185 | let field_expr = expr.syntax().text().to_string(); |
190 | if field_name == field_expr { | 186 | let field_name_is_tup_index = name_ref.as_tuple_field().is_some(); |
187 | if field_name == field_expr && !field_name_is_tup_index { | ||
191 | let mut edit_builder = TextEditBuilder::default(); | 188 | let mut edit_builder = TextEditBuilder::default(); |
192 | edit_builder.delete(record_field.syntax().text_range()); | 189 | edit_builder.delete(record_field.syntax().text_range()); |
193 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); | 190 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); |
@@ -321,29 +318,26 @@ mod tests { | |||
321 | fn test_wrap_return_type() { | 318 | fn test_wrap_return_type() { |
322 | let before = r#" | 319 | let before = r#" |
323 | //- /main.rs | 320 | //- /main.rs |
324 | use std::{string::String, result::Result::{self, Ok, Err}}; | 321 | use core::result::Result::{self, Ok, Err}; |
325 | 322 | ||
326 | fn div(x: i32, y: i32) -> Result<i32, String> { | 323 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
327 | if y == 0 { | 324 | if y == 0 { |
328 | return Err("div by zero".into()); | 325 | return Err(()); |
329 | } | 326 | } |
330 | x / y<|> | 327 | x / y<|> |
331 | } | 328 | } |
332 | 329 | ||
333 | //- /std/lib.rs | 330 | //- /core/lib.rs |
334 | pub mod string { | ||
335 | pub struct String { } | ||
336 | } | ||
337 | pub mod result { | 331 | pub mod result { |
338 | pub enum Result<T, E> { Ok(T), Err(E) } | 332 | pub enum Result<T, E> { Ok(T), Err(E) } |
339 | } | 333 | } |
340 | "#; | 334 | "#; |
341 | let after = r#" | 335 | let after = r#" |
342 | use std::{string::String, result::Result::{self, Ok, Err}}; | 336 | use core::result::Result::{self, Ok, Err}; |
343 | 337 | ||
344 | fn div(x: i32, y: i32) -> Result<i32, String> { | 338 | fn div(x: i32, y: i32) -> Result<i32, ()> { |
345 | if y == 0 { | 339 | if y == 0 { |
346 | return Err("div by zero".into()); | 340 | return Err(()); |
347 | } | 341 | } |
348 | Ok(x / y) | 342 | Ok(x / y) |
349 | } | 343 | } |
@@ -355,7 +349,7 @@ mod tests { | |||
355 | fn test_wrap_return_type_handles_generic_functions() { | 349 | fn test_wrap_return_type_handles_generic_functions() { |
356 | let before = r#" | 350 | let before = r#" |
357 | //- /main.rs | 351 | //- /main.rs |
358 | use std::result::Result::{self, Ok, Err}; | 352 | use core::result::Result::{self, Ok, Err}; |
359 | 353 | ||
360 | fn div<T>(x: T) -> Result<T, i32> { | 354 | fn div<T>(x: T) -> Result<T, i32> { |
361 | if x == 0 { | 355 | if x == 0 { |
@@ -364,13 +358,13 @@ mod tests { | |||
364 | <|>x | 358 | <|>x |
365 | } | 359 | } |
366 | 360 | ||
367 | //- /std/lib.rs | 361 | //- /core/lib.rs |
368 | pub mod result { | 362 | pub mod result { |
369 | pub enum Result<T, E> { Ok(T), Err(E) } | 363 | pub enum Result<T, E> { Ok(T), Err(E) } |
370 | } | 364 | } |
371 | "#; | 365 | "#; |
372 | let after = r#" | 366 | let after = r#" |
373 | use std::result::Result::{self, Ok, Err}; | 367 | use core::result::Result::{self, Ok, Err}; |
374 | 368 | ||
375 | fn div<T>(x: T) -> Result<T, i32> { | 369 | fn div<T>(x: T) -> Result<T, i32> { |
376 | if x == 0 { | 370 | if x == 0 { |
@@ -386,32 +380,29 @@ mod tests { | |||
386 | fn test_wrap_return_type_handles_type_aliases() { | 380 | fn test_wrap_return_type_handles_type_aliases() { |
387 | let before = r#" | 381 | let before = r#" |
388 | //- /main.rs | 382 | //- /main.rs |
389 | use std::{string::String, result::Result::{self, Ok, Err}}; | 383 | use core::result::Result::{self, Ok, Err}; |
390 | 384 | ||
391 | type MyResult<T> = Result<T, String>; | 385 | type MyResult<T> = Result<T, ()>; |
392 | 386 | ||
393 | fn div(x: i32, y: i32) -> MyResult<i32> { | 387 | fn div(x: i32, y: i32) -> MyResult<i32> { |
394 | if y == 0 { | 388 | if y == 0 { |
395 | return Err("div by zero".into()); | 389 | return Err(()); |
396 | } | 390 | } |
397 | x <|>/ y | 391 | x <|>/ y |
398 | } | 392 | } |
399 | 393 | ||
400 | //- /std/lib.rs | 394 | //- /core/lib.rs |
401 | pub mod string { | ||
402 | pub struct String { } | ||
403 | } | ||
404 | pub mod result { | 395 | pub mod result { |
405 | pub enum Result<T, E> { Ok(T), Err(E) } | 396 | pub enum Result<T, E> { Ok(T), Err(E) } |
406 | } | 397 | } |
407 | "#; | 398 | "#; |
408 | let after = r#" | 399 | let after = r#" |
409 | use std::{string::String, result::Result::{self, Ok, Err}}; | 400 | use core::result::Result::{self, Ok, Err}; |
410 | 401 | ||
411 | type MyResult<T> = Result<T, String>; | 402 | type MyResult<T> = Result<T, ()>; |
412 | fn div(x: i32, y: i32) -> MyResult<i32> { | 403 | fn div(x: i32, y: i32) -> MyResult<i32> { |
413 | if y == 0 { | 404 | if y == 0 { |
414 | return Err("div by zero".into()); | 405 | return Err(()); |
415 | } | 406 | } |
416 | Ok(x / y) | 407 | Ok(x / y) |
417 | } | 408 | } |
@@ -423,16 +414,13 @@ mod tests { | |||
423 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { | 414 | fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { |
424 | let content = r#" | 415 | let content = r#" |
425 | //- /main.rs | 416 | //- /main.rs |
426 | use std::{string::String, result::Result::{self, Ok, Err}}; | 417 | use core::result::Result::{self, Ok, Err}; |
427 | 418 | ||
428 | fn foo() -> Result<String, i32> { | 419 | fn foo() -> Result<(), i32> { |
429 | 0<|> | 420 | 0<|> |
430 | } | 421 | } |
431 | 422 | ||
432 | //- /std/lib.rs | 423 | //- /core/lib.rs |
433 | pub mod string { | ||
434 | pub struct String { } | ||
435 | } | ||
436 | pub mod result { | 424 | pub mod result { |
437 | pub enum Result<T, E> { Ok(T), Err(E) } | 425 | pub enum Result<T, E> { Ok(T), Err(E) } |
438 | } | 426 | } |
@@ -444,7 +432,7 @@ mod tests { | |||
444 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { | 432 | fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { |
445 | let content = r#" | 433 | let content = r#" |
446 | //- /main.rs | 434 | //- /main.rs |
447 | use std::{string::String, result::Result::{self, Ok, Err}}; | 435 | use core::result::Result::{self, Ok, Err}; |
448 | 436 | ||
449 | enum SomeOtherEnum { | 437 | enum SomeOtherEnum { |
450 | Ok(i32), | 438 | Ok(i32), |
@@ -455,10 +443,7 @@ mod tests { | |||
455 | 0<|> | 443 | 0<|> |
456 | } | 444 | } |
457 | 445 | ||
458 | //- /std/lib.rs | 446 | //- /core/lib.rs |
459 | pub mod string { | ||
460 | pub struct String { } | ||
461 | } | ||
462 | pub mod result { | 447 | pub mod result { |
463 | pub enum Result<T, E> { Ok(T), Err(E) } | 448 | pub enum Result<T, E> { Ok(T), Err(E) } |
464 | } | 449 | } |
@@ -623,10 +608,10 @@ mod tests { | |||
623 | source_file_edits: [], | 608 | source_file_edits: [], |
624 | file_system_edits: [ | 609 | file_system_edits: [ |
625 | CreateFile { | 610 | CreateFile { |
626 | source_root: SourceRootId( | 611 | anchor: FileId( |
627 | 0, | 612 | 1, |
628 | ), | 613 | ), |
629 | path: "foo.rs", | 614 | dst: "foo.rs", |
630 | }, | 615 | }, |
631 | ], | 616 | ], |
632 | is_snippet: false, | 617 | is_snippet: false, |
@@ -731,6 +716,18 @@ mod tests { | |||
731 | "#, | 716 | "#, |
732 | check_struct_shorthand_initialization, | 717 | check_struct_shorthand_initialization, |
733 | ); | 718 | ); |
719 | check_not_applicable( | ||
720 | r#" | ||
721 | struct A(usize); | ||
722 | |||
723 | fn main() { | ||
724 | A { | ||
725 | 0: 0 | ||
726 | } | ||
727 | } | ||
728 | "#, | ||
729 | check_struct_shorthand_initialization, | ||
730 | ); | ||
734 | 731 | ||
735 | check_apply( | 732 | check_apply( |
736 | r#" | 733 | r#" |