1 use base_db::fixture::WithFixture;
4 use test_utils::{assert_eq_text, CURSOR_MARKER};
9 fn trailing_comment_in_empty_file() {
22 ImportGranularity::Crate,
27 fn respects_cfg_attr_fn() {
40 ImportGranularity::Crate,
45 fn respects_cfg_attr_const() {
50 const FOO: Bar = {$0};
58 ImportGranularity::Crate,
63 fn insert_skips_lone_glob_imports() {
73 ImportGranularity::Crate,
78 fn insert_not_group() {
79 cov_mark::check!(insert_no_grouping_last);
81 "use external_crate2::bar::A",
84 use external_crate::bar::A;
90 use external_crate::bar::A;
94 use external_crate2::bar::A;",
96 granularity: ImportGranularity::Item,
97 enforce_granularity: true,
98 prefix_kind: PrefixKind::Plain,
100 skip_glob_imports: true,
106 fn insert_existing() {
107 check_crate("std::fs", "use std::fs;", "use std::fs;")
129 fn insert_start_indent() {
144 cov_mark::check!(insert_group);
162 fn insert_middle_indent() {
181 cov_mark::check!(insert_group_last);
199 fn insert_end_indent() {
217 fn insert_middle_nested() {
222 use std::bar::{D, Z}; // example of weird imports due to user
228 use std::bar::{D, Z}; // example of weird imports due to user
235 fn insert_middle_groups() {
255 fn insert_first_matching_group() {
279 fn insert_missing_group_std() {
280 cov_mark::check!(insert_group_new_group);
295 fn insert_missing_group_self() {
296 cov_mark::check!(insert_group_no_group);
311 fn insert_no_imports() {
322 fn insert_empty_file() {
323 cov_mark::check_count!(insert_empty_file, 2);
325 // Default configuration
326 // empty files will get two trailing newlines
327 // this is due to the test case insert_no_imports above
336 // "not group" configuration
338 "use external_crate2::bar::A",
340 r"use external_crate2::bar::A;
344 granularity: ImportGranularity::Item,
345 enforce_granularity: true,
346 prefix_kind: PrefixKind::Plain,
348 skip_glob_imports: true,
354 fn insert_empty_module() {
355 cov_mark::check_count!(insert_empty_module, 2);
357 // Default configuration
368 ImportGranularity::Item,
371 // "not group" configuration
379 granularity: ImportGranularity::Item,
380 enforce_granularity: true,
381 prefix_kind: PrefixKind::Plain,
383 skip_glob_imports: true,
389 fn insert_after_inner_attr() {
390 cov_mark::check_count!(insert_empty_inner_attr, 2);
392 // Default configuration
395 r"#![allow(unused_imports)]",
396 r"#![allow(unused_imports)]
401 // "not group" configuration
404 r"#![allow(unused_imports)]",
405 r"#![allow(unused_imports)]
409 granularity: ImportGranularity::Item,
410 enforce_granularity: true,
411 prefix_kind: PrefixKind::Plain,
413 skip_glob_imports: true,
419 fn insert_after_inner_attr2() {
422 r"#![allow(unused_imports)]
426 r"#![allow(unused_imports)]
436 fn inserts_after_single_line_inner_comments() {
439 "//! Single line inner comments do not allow any code before them.",
440 r#"//! Single line inner comments do not allow any code before them.
442 use foo::bar::Baz;"#,
447 //! Single line inner comments do not allow any code before them.
451 //! Single line inner comments do not allow any code before them.
460 fn inserts_after_single_line_comments() {
463 "// Represents a possible license header and/or general module comments",
464 r#"// Represents a possible license header and/or general module comments
466 use foo::bar::Baz;"#,
471 fn inserts_after_shebang() {
474 "#!/usr/bin/env rust",
475 r#"#!/usr/bin/env rust
477 use foo::bar::Baz;"#,
482 fn inserts_after_multiple_single_line_comments() {
485 "// Represents a possible license header and/or general module comments
486 // Second single-line comment
487 // Third single-line comment",
488 r#"// Represents a possible license header and/or general module comments
489 // Second single-line comment
490 // Third single-line comment
492 use foo::bar::Baz;"#,
497 fn inserts_before_single_line_item_comments() {
500 r#"// Represents a comment about a function
502 r#"use foo::bar::Baz;
504 // Represents a comment about a function
510 fn inserts_after_single_line_header_comments_and_before_item() {
513 r#"// Represents a possible license header
514 // Line two of possible license header
517 r#"// Represents a possible license header
518 // Line two of possible license header
527 fn inserts_after_multiline_inner_comments() {
530 r#"/*! Multiline inner comments do not allow any code before them. */
532 /*! Still an inner comment, cannot place any code before. */
534 r#"/*! Multiline inner comments do not allow any code before them. */
536 /*! Still an inner comment, cannot place any code before. */
544 fn inserts_after_all_inner_items() {
547 r#"#![allow(unused_imports)]
548 /*! Multiline line comment 2 */
551 //! Single line comment 1
553 //! Single line comment 2
555 r#"#![allow(unused_imports)]
556 /*! Multiline line comment 2 */
559 //! Single line comment 1
561 //! Single line comment 2
570 check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};")
574 fn merge_groups_last() {
577 r"use std::fmt::{Result, Display};",
578 r"use std::fmt::{Result, Display};
584 fn merge_last_into_self() {
585 check_module("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};");
589 fn merge_groups_full() {
592 r"use std::fmt::{Result, Display};",
593 r"use std::{fmt::{Result, Display}, io};",
598 fn merge_groups_long_full() {
599 check_crate("std::foo::bar::Baz", r"use std::foo::bar::Qux;", r"use std::foo::bar::{Qux, Baz};")
603 fn merge_groups_long_last() {
605 "std::foo::bar::Baz",
606 r"use std::foo::bar::Qux;",
607 r"use std::foo::bar::{Qux, Baz};",
612 fn merge_groups_long_full_list() {
614 "std::foo::bar::Baz",
615 r"use std::foo::bar::{Qux, Quux};",
616 r"use std::foo::bar::{Qux, Quux, Baz};",
621 fn merge_groups_long_last_list() {
623 "std::foo::bar::Baz",
624 r"use std::foo::bar::{Qux, Quux};",
625 r"use std::foo::bar::{Qux, Quux, Baz};",
630 fn merge_groups_long_full_nested() {
632 "std::foo::bar::Baz",
633 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
634 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}, Baz};",
639 fn merge_groups_long_last_nested() {
641 "std::foo::bar::Baz",
642 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
643 r"use std::foo::bar::Baz;
644 use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
649 fn merge_groups_full_nested_deep() {
651 "std::foo::bar::quux::Baz",
652 r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};",
653 r"use std::foo::bar::{Qux, quux::{Fez, Fizz, Baz}};",
658 fn merge_groups_full_nested_long() {
660 "std::foo::bar::Baz",
661 r"use std::{foo::bar::Qux};",
662 r"use std::{foo::bar::{Qux, Baz}};",
667 fn merge_groups_last_nested_long() {
669 "std::foo::bar::Baz",
670 r"use std::{foo::bar::Qux};",
671 r"use std::{foo::bar::{Qux, Baz}};",
676 fn merge_groups_skip_pub() {
679 r"pub use std::fmt::{Result, Display};",
680 r"pub use std::fmt::{Result, Display};
686 fn merge_groups_skip_pub_crate() {
689 r"pub(crate) use std::fmt::{Result, Display};",
690 r"pub(crate) use std::fmt::{Result, Display};
696 fn merge_groups_skip_attributed() {
700 #[cfg(feature = "gated")] use std::fmt::{Result, Display};
703 #[cfg(feature = "gated")] use std::fmt::{Result, Display};
710 fn split_out_merge() {
711 // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}`
715 r"use std::{fmt, io};",
716 r"use std::fmt::Result;
717 use std::{fmt, io};",
722 fn merge_into_module_import() {
723 check_crate("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};")
727 fn merge_groups_self() {
728 check_crate("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};")
732 fn merge_mod_into_glob() {
735 r"use token::TokenKind::*;",
736 r"use token::TokenKind::{*, self};",
738 granularity: ImportGranularity::Crate,
739 enforce_granularity: true,
740 prefix_kind: PrefixKind::Plain,
742 skip_glob_imports: false,
745 // FIXME: have it emit `use token::TokenKind::{self, *}`?
749 fn merge_self_glob() {
753 r"use self::{*, self};",
755 granularity: ImportGranularity::Crate,
756 enforce_granularity: true,
757 prefix_kind: PrefixKind::Plain,
759 skip_glob_imports: false,
762 // FIXME: have it emit `use {self, *}`?
768 "syntax::SyntaxKind",
770 use syntax::{SyntaxKind::*};",
772 use syntax::{SyntaxKind::{*, self}};",
777 fn merge_glob_nested() {
779 "foo::bar::quux::Fez",
780 r"use foo::bar::{Baz, quux::*};",
781 r"use foo::bar::{Baz, quux::{*, Fez}};",
786 fn merge_nested_considers_first_segments() {
788 "hir_ty::display::write_bounds_like_dyn_trait",
789 r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};",
790 r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter, write_bounds_like_dyn_trait}, method_resolution};",
795 fn skip_merge_last_too_long() {
798 r"use foo::bar::baz::Qux;",
800 use foo::bar::baz::Qux;",
805 fn skip_merge_last_too_long2() {
807 "foo::bar::baz::Qux",
810 use foo::bar::baz::Qux;",
815 fn insert_short_before_long() {
818 r"use foo::bar::baz::Qux;",
820 use foo::bar::baz::Qux;",
825 fn merge_last_fail() {
826 check_merge_only_fail(
827 r"use foo::bar::{baz::{Qux, Fez}};",
828 r"use foo::bar::{baaz::{Quux, Feez}};",
829 MergeBehavior::Module,
834 fn merge_last_fail1() {
835 check_merge_only_fail(
836 r"use foo::bar::{baz::{Qux, Fez}};",
837 r"use foo::bar::baaz::{Quux, Feez};",
838 MergeBehavior::Module,
843 fn merge_last_fail2() {
844 check_merge_only_fail(
845 r"use foo::bar::baz::{Qux, Fez};",
846 r"use foo::bar::{baaz::{Quux, Feez}};",
847 MergeBehavior::Module,
852 fn merge_last_fail3() {
853 check_merge_only_fail(
854 r"use foo::bar::baz::{Qux, Fez};",
855 r"use foo::bar::baaz::{Quux, Feez};",
856 MergeBehavior::Module,
862 check_guess("", ImportGranularityGuess::Unknown);
867 check_guess(r"use foo::{baz::{qux, quux}, bar};", ImportGranularityGuess::Crate);
868 check_guess(r"use foo::bar;", ImportGranularityGuess::Unknown);
869 check_guess(r"use foo::bar::{baz, qux};", ImportGranularityGuess::CrateOrModule);
879 ImportGranularityGuess::Unknown,
890 ImportGranularityGuess::Item,
895 fn guess_module_or_item() {
901 ImportGranularityGuess::ModuleOrItem,
908 ImportGranularityGuess::ModuleOrItem,
917 use foo::bar::{qux, quux};
919 ImportGranularityGuess::Module,
921 // this is a rather odd case, technically this file isn't following any style properly.
925 use foo::{baz::{qux, quux}, bar};
927 ImportGranularityGuess::Module,
935 ImportGranularityGuess::Module,
940 fn guess_crate_or_module() {
944 use oof::bar::{qux, quux};
946 ImportGranularityGuess::CrateOrModule,
955 use foo::{baz::{qux, quux}, bar};
957 ImportGranularityGuess::Crate,
962 fn guess_skips_differing_vis() {
966 pub use foo::bar::qux;
968 ImportGranularityGuess::Unknown,
973 fn guess_skips_differing_attrs() {
976 pub use foo::bar::baz;
978 pub use foo::bar::qux;
980 ImportGranularityGuess::Unknown,
985 fn guess_grouping_matters() {
992 ImportGranularityGuess::Unknown,
996 fn check_with_config(
998 ra_fixture_before: &str,
999 ra_fixture_after: &str,
1000 config: &InsertUseConfig,
1002 let (db, file_id, pos) = if ra_fixture_before.contains(CURSOR_MARKER) {
1003 let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture_before);
1004 (db, file_id, Some(range_or_offset))
1006 let (db, file_id) = RootDatabase::with_single_file(ra_fixture_before);
1009 let sema = &Semantics::new(&db);
1010 let source_file = sema.parse(file_id);
1011 let syntax = source_file.syntax().clone_for_update();
1013 .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent())
1014 .and_then(|it| ImportScope::find_insert_use_container(&it, sema))
1015 .or_else(|| ImportScope::from(syntax))
1017 let path = ast::SourceFile::parse(&format!("use {};", path))
1021 .find_map(ast::Path::cast)
1024 insert_use(&file, path, config);
1025 let result = file.as_syntax_node().ancestors().last().unwrap().to_string();
1026 assert_eq_text!(&trim_indent(ra_fixture_after), &result);
1031 ra_fixture_before: &str,
1032 ra_fixture_after: &str,
1033 granularity: ImportGranularity,
1041 enforce_granularity: true,
1042 prefix_kind: PrefixKind::Plain,
1044 skip_glob_imports: true,
1049 fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1050 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate)
1053 fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1054 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module)
1057 fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
1058 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item)
1061 fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) {
1062 let use0 = ast::SourceFile::parse(ra_fixture0)
1066 .find_map(ast::Use::cast)
1069 let use1 = ast::SourceFile::parse(ra_fixture1)
1073 .find_map(ast::Use::cast)
1076 let result = try_merge_imports(&use0, &use1, mb);
1077 assert_eq!(result.map(|u| u.to_string()), None);
1080 fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) {
1081 let syntax = ast::SourceFile::parse(ra_fixture).tree().syntax().clone();
1082 let file = ImportScope::from(syntax).unwrap();
1083 assert_eq!(super::guess_granularity_from_scope(&file), expected);