]> git.lizzy.rs Git - rust.git/blobdiff - crates/ide_assists/src/handlers/qualify_path.rs
Merge #11481
[rust.git] / crates / ide_assists / src / handlers / qualify_path.rs
index f91770a763750cf2559859d66d7139350be91c9f..ae29068bd702a1d1ece31460afa035d630cba641 100644 (file)
@@ -8,8 +8,8 @@
 use ide_db::RootDatabase;
 use syntax::{
     ast,
-    ast::{make, ArgListOwner},
-    AstNode,
+    ast::{make, HasArgList},
+    AstNode, NodeOrToken,
 };
 
 use crate::{
 // ```
 pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
-    let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
+    let mut proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
     if proposed_imports.is_empty() {
         return None;
     }
 
-    let range = ctx.sema.original_range(&syntax_under_caret).range;
+    let range = match &syntax_under_caret {
+        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
+        NodeOrToken::Token(token) => token.text_range(),
+    };
     let candidate = import_assets.import_candidate();
-    let qualify_candidate = match candidate {
-        ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
-            cov_mark::hit!(qualify_path_qualifier_start);
-            let path = ast::Path::cast(syntax_under_caret)?;
-            let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
-            QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
-        }
-        ImportCandidate::Path(_) => {
-            cov_mark::hit!(qualify_path_unqualified_name);
-            let path = ast::Path::cast(syntax_under_caret)?;
-            let generics = path.segment()?.generic_arg_list();
-            QualifyCandidate::UnqualifiedName(generics)
-        }
-        ImportCandidate::TraitAssocItem(_) => {
-            cov_mark::hit!(qualify_path_trait_assoc_item);
-            let path = ast::Path::cast(syntax_under_caret)?;
-            let (qualifier, segment) = (path.qualifier()?, path.segment()?);
-            QualifyCandidate::TraitAssocItem(qualifier, segment)
-        }
-        ImportCandidate::TraitMethod(_) => {
-            cov_mark::hit!(qualify_path_trait_method);
-            let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
-            QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
-        }
+    let qualify_candidate = match syntax_under_caret {
+        NodeOrToken::Node(syntax_under_caret) => match candidate {
+            ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
+                cov_mark::hit!(qualify_path_qualifier_start);
+                let path = ast::Path::cast(syntax_under_caret)?;
+                let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?);
+                QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list())
+            }
+            ImportCandidate::Path(_) => {
+                cov_mark::hit!(qualify_path_unqualified_name);
+                let path = ast::Path::cast(syntax_under_caret)?;
+                let generics = path.segment()?.generic_arg_list();
+                QualifyCandidate::UnqualifiedName(generics)
+            }
+            ImportCandidate::TraitAssocItem(_) => {
+                cov_mark::hit!(qualify_path_trait_assoc_item);
+                let path = ast::Path::cast(syntax_under_caret)?;
+                let (qualifier, segment) = (path.qualifier()?, path.segment()?);
+                QualifyCandidate::TraitAssocItem(qualifier, segment)
+            }
+            ImportCandidate::TraitMethod(_) => {
+                cov_mark::hit!(qualify_path_trait_method);
+                let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?;
+                QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr)
+            }
+        },
+        // derive attribute path
+        NodeOrToken::Token(_) => QualifyCandidate::UnqualifiedName(None),
     };
 
+    // we aren't interested in different namespaces
+    proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
+
     let group_label = group_label(candidate);
     for import in proposed_imports {
         acc.add_group(
@@ -88,16 +98,16 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
     }
     Some(())
 }
-
-enum QualifyCandidate<'db> {
+pub(crate) enum QualifyCandidate<'db> {
     QualifierStart(ast::PathSegment, Option<ast::GenericArgList>),
     UnqualifiedName(Option<ast::GenericArgList>),
     TraitAssocItem(ast::Path, ast::PathSegment),
     TraitMethod(&'db RootDatabase, ast::MethodCallExpr),
+    ImplMethod(&'db RootDatabase, ast::MethodCallExpr, hir::Function),
 }
 
 impl QualifyCandidate<'_> {
-    fn qualify(
+    pub(crate) fn qualify(
         &self,
         mut replacer: impl FnMut(String),
         import: &hir::ModPath,
@@ -111,7 +121,7 @@ fn qualify(
             }
             QualifyCandidate::UnqualifiedName(generics) => {
                 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
-                replacer(format!("{}{}", import.to_string(), generics));
+                replacer(format!("{}{}", import, generics));
             }
             QualifyCandidate::TraitAssocItem(qualifier, segment) => {
                 replacer(format!("<{} as {}>::{}", qualifier, import, segment));
@@ -119,24 +129,26 @@ fn qualify(
             QualifyCandidate::TraitMethod(db, mcall_expr) => {
                 Self::qualify_trait_method(db, mcall_expr, replacer, import, item);
             }
+            QualifyCandidate::ImplMethod(db, mcall_expr, hir_fn) => {
+                Self::qualify_fn_call(db, mcall_expr, replacer, import, hir_fn);
+            }
         }
     }
 
-    fn qualify_trait_method(
+    fn qualify_fn_call(
         db: &RootDatabase,
         mcall_expr: &ast::MethodCallExpr,
         mut replacer: impl FnMut(String),
         import: ast::Path,
-        item: hir::ItemInNs,
+        hir_fn: &hir::Function,
     ) -> Option<()> {
         let receiver = mcall_expr.receiver()?;
-        let trait_method_name = mcall_expr.name_ref()?;
+        let method_name = mcall_expr.name_ref()?;
         let generics =
             mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string);
         let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args());
-        let trait_ = item_as_trait(db, item)?;
-        let method = find_trait_method(db, trait_, &trait_method_name)?;
-        if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) {
+
+        if let Some(self_access) = hir_fn.self_param(db).map(|sp| sp.access(db)) {
             let receiver = match self_access {
                 hir::Access::Shared => make::expr_ref(receiver, false),
                 hir::Access::Exclusive => make::expr_ref(receiver, true),
@@ -145,7 +157,7 @@ fn qualify_trait_method(
             replacer(format!(
                 "{}::{}{}{}",
                 import,
-                trait_method_name,
+                method_name,
                 generics,
                 match arg_list {
                     Some(args) => make::arg_list(iter::once(receiver).chain(args)),
@@ -155,6 +167,19 @@ fn qualify_trait_method(
         }
         Some(())
     }
+
+    fn qualify_trait_method(
+        db: &RootDatabase,
+        mcall_expr: &ast::MethodCallExpr,
+        replacer: impl FnMut(String),
+        import: ast::Path,
+        item: hir::ItemInNs,
+    ) -> Option<()> {
+        let trait_method_name = mcall_expr.name_ref()?;
+        let trait_ = item_as_trait(db, item)?;
+        let method = find_trait_method(db, trait_, &trait_method_name)?;
+        Self::qualify_fn_call(db, mcall_expr, replacer, import, &method)
+    }
 }
 
 fn find_trait_method(
@@ -176,12 +201,11 @@ fn find_trait_method(
 }
 
 fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
-    let item_module_def = hir::ModuleDef::from(item.as_module_def_id()?);
+    let item_module_def = item.as_module_def()?;
 
-    if let hir::ModuleDef::Trait(trait_) = item_module_def {
-        Some(trait_)
-    } else {
-        item_module_def.as_assoc_item(db)?.containing_trait(db)
+    match item_module_def {
+        hir::ModuleDef::Trait(trait_) => Some(trait_),
+        _ => item_module_def.as_assoc_item(db)?.containing_trait(db),
     }
 }
 
@@ -216,28 +240,28 @@ fn applicable_when_found_an_import_partial() {
         cov_mark::check!(qualify_path_unqualified_name);
         check_assist(
             qualify_path,
-            r"
-            mod std {
-                pub mod fmt {
-                    pub struct Formatter;
-                }
-            }
+            r#"
+mod std {
+    pub mod fmt {
+        pub struct Formatter;
+    }
+}
 
-            use std::fmt;
+use std::fmt;
 
-            $0Formatter
-            ",
-            r"
-            mod std {
-                pub mod fmt {
-                    pub struct Formatter;
-                }
-            }
+$0Formatter
+"#,
+            r#"
+mod std {
+    pub mod fmt {
+        pub struct Formatter;
+    }
+}
 
-            use std::fmt;
+use std::fmt;
 
-            fmt::Formatter
-            ",
+fmt::Formatter
+"#,
         );
     }
 
@@ -245,20 +269,20 @@ pub mod fmt {
     fn applicable_when_found_an_import() {
         check_assist(
             qualify_path,
-            r"
-            $0PubStruct
+            r#"
+$0PubStruct
 
-            pub mod PubMod {
-                pub struct PubStruct;
-            }
-            ",
-            r"
-            PubMod::PubStruct
+pub mod PubMod {
+    pub struct PubStruct;
+}
+"#,
+            r#"
+PubMod::PubStruct
 
-            pub mod PubMod {
-                pub struct PubStruct;
-            }
-            ",
+pub mod PubMod {
+    pub struct PubStruct;
+}
+"#,
         );
     }
 
@@ -266,26 +290,26 @@ pub mod PubMod {
     fn applicable_in_macros() {
         check_assist(
             qualify_path,
-            r"
-            macro_rules! foo {
-                ($i:ident) => { fn foo(a: $i) {} }
-            }
-            foo!(Pub$0Struct);
+            r#"
+macro_rules! foo {
+    ($i:ident) => { fn foo(a: $i) {} }
+}
+foo!(Pub$0Struct);
 
-            pub mod PubMod {
-                pub struct PubStruct;
-            }
-            ",
-            r"
-            macro_rules! foo {
-                ($i:ident) => { fn foo(a: $i) {} }
-            }
-            foo!(PubMod::PubStruct);
+pub mod PubMod {
+    pub struct PubStruct;
+}
+"#,
+            r#"
+macro_rules! foo {
+    ($i:ident) => { fn foo(a: $i) {} }
+}
+foo!(PubMod::PubStruct);
 
-            pub mod PubMod {
-                pub struct PubStruct;
-            }
-            ",
+pub mod PubMod {
+    pub struct PubStruct;
+}
+"#,
         );
     }
 
@@ -293,32 +317,32 @@ pub mod PubMod {
     fn applicable_when_found_multiple_imports() {
         check_assist(
             qualify_path,
-            r"
-            PubSt$0ruct
+            r#"
+PubSt$0ruct
 
-            pub mod PubMod1 {
-                pub struct PubStruct;
-            }
-            pub mod PubMod2 {
-                pub struct PubStruct;
-            }
-            pub mod PubMod3 {
-                pub struct PubStruct;
-            }
-            ",
-            r"
-            PubMod3::PubStruct
+pub mod PubMod1 {
+    pub struct PubStruct;
+}
+pub mod PubMod2 {
+    pub struct PubStruct;
+}
+pub mod PubMod3 {
+    pub struct PubStruct;
+}
+"#,
+            r#"
+PubMod3::PubStruct
 
-            pub mod PubMod1 {
-                pub struct PubStruct;
-            }
-            pub mod PubMod2 {
-                pub struct PubStruct;
-            }
-            pub mod PubMod3 {
-                pub struct PubStruct;
-            }
-            ",
+pub mod PubMod1 {
+    pub struct PubStruct;
+}
+pub mod PubMod2 {
+    pub struct PubStruct;
+}
+pub mod PubMod3 {
+    pub struct PubStruct;
+}
+"#,
         );
     }
 
@@ -326,15 +350,15 @@ pub mod PubMod3 {
     fn not_applicable_for_already_imported_types() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            use PubMod::PubStruct;
+            r#"
+use PubMod::PubStruct;
 
-            PubStruct$0
+PubStruct$0
 
-            pub mod PubMod {
-                pub struct PubStruct;
-            }
-            ",
+pub mod PubMod {
+    pub struct PubStruct;
+}
+"#,
         );
     }
 
@@ -342,35 +366,32 @@ pub mod PubMod {
     fn not_applicable_for_types_with_private_paths() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            PrivateStruct$0
+            r#"
+PrivateStruct$0
 
-            pub mod PubMod {
-                struct PrivateStruct;
-            }
-            ",
+pub mod PubMod {
+    struct PrivateStruct;
+}
+"#,
         );
     }
 
     #[test]
     fn not_applicable_when_no_imports_found() {
-        check_assist_not_applicable(
-            qualify_path,
-            "
-            PubStruct$0",
-        );
+        check_assist_not_applicable(qualify_path, r#"PubStruct$0"#);
     }
 
     #[test]
     fn not_applicable_in_import_statements() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            use PubStruct$0;
+            r#"
+use PubStruct$0;
 
-            pub mod PubMod {
-                pub struct PubStruct;
-            }",
+pub mod PubMod {
+    pub struct PubStruct;
+}
+"#,
         );
     }
 
@@ -378,20 +399,20 @@ pub mod PubMod {
     fn qualify_function() {
         check_assist(
             qualify_path,
-            r"
-            test_function$0
+            r#"
+test_function$0
 
-            pub mod PubMod {
-                pub fn test_function() {};
-            }
-            ",
-            r"
-            PubMod::test_function
+pub mod PubMod {
+    pub fn test_function() {};
+}
+"#,
+            r#"
+PubMod::test_function
 
-            pub mod PubMod {
-                pub fn test_function() {};
-            }
-            ",
+pub mod PubMod {
+    pub fn test_function() {};
+}
+"#,
         );
     }
 
@@ -399,7 +420,7 @@ pub mod PubMod {
     fn qualify_macro() {
         check_assist(
             qualify_path,
-            r"
+            r#"
 //- /lib.rs crate:crate_with_macro
 #[macro_export]
 macro_rules! foo {
@@ -410,12 +431,12 @@ macro_rules! foo {
 fn main() {
     foo$0
 }
-",
-            r"
+"#,
+            r#"
 fn main() {
     crate_with_macro::foo
 }
-",
+"#,
         );
     }
 
@@ -423,13 +444,13 @@ fn main() {
     fn qualify_path_target() {
         check_assist_target(
             qualify_path,
-            r"
-            struct AssistInfo {
-                group_label: Option<$0GroupLabel>,
-            }
+            r#"
+struct AssistInfo {
+    group_label: Option<$0GroupLabel>,
+}
 
-            mod m { pub struct GroupLabel; }
-            ",
+mod m { pub struct GroupLabel; }
+"#,
             "GroupLabel",
         )
     }
@@ -438,20 +459,20 @@ struct AssistInfo {
     fn not_applicable_when_path_start_is_imported() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            pub mod mod1 {
-                pub mod mod2 {
-                    pub mod mod3 {
-                        pub struct TestStruct;
-                    }
-                }
-            }
+            r#"
+pub mod mod1 {
+    pub mod mod2 {
+        pub mod mod3 {
+            pub struct TestStruct;
+        }
+    }
+}
 
-            use mod1::mod2;
-            fn main() {
-                mod2::mod3::TestStruct$0
-            }
-            ",
+use mod1::mod2;
+fn main() {
+    mod2::mod3::TestStruct$0
+}
+"#,
         );
     }
 
@@ -459,16 +480,16 @@ fn main() {
     fn not_applicable_for_imported_function() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            pub mod test_mod {
-                pub fn test_function() {}
-            }
+            r#"
+pub mod test_mod {
+    pub fn test_function() {}
+}
 
-            use test_mod::test_function;
-            fn main() {
-                test_function$0
-            }
-            ",
+use test_mod::test_function;
+fn main() {
+    test_function$0
+}
+"#,
         );
     }
 
@@ -476,30 +497,30 @@ fn main() {
     fn associated_struct_function() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    pub fn test_function() {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub struct TestStruct {}
+    impl TestStruct {
+        pub fn test_function() {}
+    }
+}
 
-            fn main() {
-                TestStruct::test_function$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    pub fn test_function() {}
-                }
-            }
+fn main() {
+    TestStruct::test_function$0
+}
+"#,
+            r#"
+mod test_mod {
+    pub struct TestStruct {}
+    impl TestStruct {
+        pub fn test_function() {}
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::test_function
-            }
-            ",
+fn main() {
+    test_mod::TestStruct::test_function
+}
+"#,
         );
     }
 
@@ -508,62 +529,50 @@ fn associated_struct_const() {
         cov_mark::check!(qualify_path_qualifier_start);
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+            r#"
+mod test_mod {
+    pub struct TestStruct {}
+    impl TestStruct {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                TestStruct::TEST_CONST$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+fn main() {
+    TestStruct::TEST_CONST$0
+}
+"#,
+            r#"
+mod test_mod {
+    pub struct TestStruct {}
+    impl TestStruct {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::TEST_CONST
-            }
-            ",
+fn main() {
+    test_mod::TestStruct::TEST_CONST
+}
+"#,
         );
     }
 
     #[test]
-    #[ignore = "FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details"]
     fn associated_struct_const_unqualified() {
-        check_assist(
+        // FIXME: non-trait assoc items completion is unsupported yet, see FIXME in the import_assets.rs for more details
+        check_assist_not_applicable(
             qualify_path,
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
-
-            fn main() {
-                TEST_CONST$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub struct TestStruct {}
-                impl TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+            r#"
+mod test_mod {
+    pub struct TestStruct {}
+    impl TestStruct {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::TEST_CONST
-            }
-            ",
+fn main() {
+    TEST_CONST$0
+}
+"#,
         );
     }
 
@@ -571,36 +580,36 @@ fn main() {
     fn associated_trait_function() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_function();
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_function() {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_function();
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_function() {}
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::test_function$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_function();
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_function() {}
-                }
-            }
+fn main() {
+    test_mod::TestStruct::test_function$0
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_function();
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_function() {}
+    }
+}
 
-            fn main() {
-                <test_mod::TestStruct as test_mod::TestTrait>::test_function
-            }
-            ",
+fn main() {
+    <test_mod::TestStruct as test_mod::TestTrait>::test_function
+}
+"#,
         );
     }
 
@@ -608,31 +617,31 @@ fn main() {
     fn not_applicable_for_imported_trait_for_function() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_function();
-                }
-                pub trait TestTrait2 {
-                    fn test_function();
-                }
-                pub enum TestEnum {
-                    One,
-                    Two,
-                }
-                impl TestTrait2 for TestEnum {
-                    fn test_function() {}
-                }
-                impl TestTrait for TestEnum {
-                    fn test_function() {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_function();
+    }
+    pub trait TestTrait2 {
+        fn test_function();
+    }
+    pub enum TestEnum {
+        One,
+        Two,
+    }
+    impl TestTrait2 for TestEnum {
+        fn test_function() {}
+    }
+    impl TestTrait for TestEnum {
+        fn test_function() {}
+    }
+}
 
-            use test_mod::TestTrait2;
-            fn main() {
-                test_mod::TestEnum::test_function$0;
-            }
-            ",
+use test_mod::TestTrait2;
+fn main() {
+    test_mod::TestEnum::test_function$0;
+}
+"#,
         )
     }
 
@@ -641,36 +650,36 @@ fn associated_trait_const() {
         cov_mark::check!(qualify_path_trait_assoc_item);
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    const TEST_CONST: u8;
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        const TEST_CONST: u8;
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::TEST_CONST$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    const TEST_CONST: u8;
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+fn main() {
+    test_mod::TestStruct::TEST_CONST$0
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        const TEST_CONST: u8;
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
-            }
-            ",
+fn main() {
+    <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST
+}
+"#,
         );
     }
 
@@ -678,31 +687,31 @@ fn main() {
     fn not_applicable_for_imported_trait_for_const() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    const TEST_CONST: u8;
-                }
-                pub trait TestTrait2 {
-                    const TEST_CONST: f64;
-                }
-                pub enum TestEnum {
-                    One,
-                    Two,
-                }
-                impl TestTrait2 for TestEnum {
-                    const TEST_CONST: f64 = 42.0;
-                }
-                impl TestTrait for TestEnum {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        const TEST_CONST: u8;
+    }
+    pub trait TestTrait2 {
+        const TEST_CONST: f64;
+    }
+    pub enum TestEnum {
+        One,
+        Two,
+    }
+    impl TestTrait2 for TestEnum {
+        const TEST_CONST: f64 = 42.0;
+    }
+    impl TestTrait for TestEnum {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            use test_mod::TestTrait2;
-            fn main() {
-                test_mod::TestEnum::TEST_CONST$0;
-            }
-            ",
+use test_mod::TestTrait2;
+fn main() {
+    test_mod::TestEnum::TEST_CONST$0;
+}
+"#,
         )
     }
 
@@ -711,38 +720,38 @@ fn trait_method() {
         cov_mark::check!(qualify_path_trait_method);
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(&self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(&self) {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(&self) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_struct.test_meth$0od()
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(&self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(&self) {}
-                }
-            }
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_struct.test_meth$0od()
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(&self) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_mod::TestTrait::test_method(&test_struct)
-            }
-            ",
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_mod::TestTrait::test_method(&test_struct)
+}
+"#,
         );
     }
 
@@ -750,38 +759,38 @@ fn main() {
     fn trait_method_multi_params() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(&self, test: i32);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(&self, test: i32) {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(&self, test: i32);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(&self, test: i32) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_struct.test_meth$0od(42)
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(&self, test: i32);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(&self, test: i32) {}
-                }
-            }
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_struct.test_meth$0od(42)
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(&self, test: i32);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(&self, test: i32) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_mod::TestTrait::test_method(&test_struct, 42)
-            }
-            ",
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_mod::TestTrait::test_method(&test_struct, 42)
+}
+"#,
         );
     }
 
@@ -789,38 +798,38 @@ fn main() {
     fn trait_method_consume() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(self) {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(self) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_struct.test_meth$0od()
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(self) {}
-                }
-            }
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_struct.test_meth$0od()
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(self) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_mod::TestTrait::test_method(test_struct)
-            }
-            ",
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_mod::TestTrait::test_method(test_struct)
+}
+"#,
         );
     }
 
@@ -828,29 +837,29 @@ fn main() {
     fn trait_method_cross_crate() {
         check_assist(
             qualify_path,
-            r"
-            //- /main.rs crate:main deps:dep
-            fn main() {
-                let test_struct = dep::test_mod::TestStruct {};
-                test_struct.test_meth$0od()
-            }
-            //- /dep.rs crate:dep
-            pub mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(&self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(&self) {}
-                }
-            }
-            ",
-            r"
-            fn main() {
-                let test_struct = dep::test_mod::TestStruct {};
-                dep::test_mod::TestTrait::test_method(&test_struct)
-            }
-            ",
+            r#"
+//- /main.rs crate:main deps:dep
+fn main() {
+    let test_struct = dep::test_mod::TestStruct {};
+    test_struct.test_meth$0od()
+}
+//- /dep.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        fn test_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(&self) {}
+    }
+}
+"#,
+            r#"
+fn main() {
+    let test_struct = dep::test_mod::TestStruct {};
+    dep::test_mod::TestTrait::test_method(&test_struct)
+}
+"#,
         );
     }
 
@@ -858,27 +867,27 @@ fn main() {
     fn assoc_fn_cross_crate() {
         check_assist(
             qualify_path,
-            r"
-            //- /main.rs crate:main deps:dep
-            fn main() {
-                dep::test_mod::TestStruct::test_func$0tion
-            }
-            //- /dep.rs crate:dep
-            pub mod test_mod {
-                pub trait TestTrait {
-                    fn test_function();
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_function() {}
-                }
-            }
-            ",
-            r"
-            fn main() {
-                <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
-            }
-            ",
+            r#"
+//- /main.rs crate:main deps:dep
+fn main() {
+    dep::test_mod::TestStruct::test_func$0tion
+}
+//- /dep.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        fn test_function();
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_function() {}
+    }
+}
+"#,
+            r#"
+fn main() {
+    <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function
+}
+"#,
         );
     }
 
@@ -886,27 +895,27 @@ fn main() {
     fn assoc_const_cross_crate() {
         check_assist(
             qualify_path,
-            r"
-            //- /main.rs crate:main deps:dep
-            fn main() {
-                dep::test_mod::TestStruct::CONST$0
-            }
-            //- /dep.rs crate:dep
-            pub mod test_mod {
-                pub trait TestTrait {
-                    const CONST: bool;
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    const CONST: bool = true;
-                }
-            }
-            ",
-            r"
-            fn main() {
-                <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
-            }
-            ",
+            r#"
+//- /main.rs crate:main deps:dep
+fn main() {
+    dep::test_mod::TestStruct::CONST$0
+}
+//- /dep.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        const CONST: bool;
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        const CONST: bool = true;
+    }
+}
+"#,
+            r#"
+fn main() {
+    <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST
+}
+"#,
         );
     }
 
@@ -914,23 +923,23 @@ fn main() {
     fn assoc_fn_as_method_cross_crate() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            //- /main.rs crate:main deps:dep
-            fn main() {
-                let test_struct = dep::test_mod::TestStruct {};
-                test_struct.test_func$0tion()
-            }
-            //- /dep.rs crate:dep
-            pub mod test_mod {
-                pub trait TestTrait {
-                    fn test_function();
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_function() {}
-                }
-            }
-            ",
+            r#"
+//- /main.rs crate:main deps:dep
+fn main() {
+    let test_struct = dep::test_mod::TestStruct {};
+    test_struct.test_func$0tion()
+}
+//- /dep.rs crate:dep
+pub mod test_mod {
+    pub trait TestTrait {
+        fn test_function();
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_function() {}
+    }
+}
+"#,
         );
     }
 
@@ -938,23 +947,23 @@ fn test_function() {}
     fn private_trait_cross_crate() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            //- /main.rs crate:main deps:dep
-            fn main() {
-                let test_struct = dep::test_mod::TestStruct {};
-                test_struct.test_meth$0od()
-            }
-            //- /dep.rs crate:dep
-            pub mod test_mod {
-                trait TestTrait {
-                    fn test_method(&self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method(&self) {}
-                }
-            }
-            ",
+            r#"
+//- /main.rs crate:main deps:dep
+fn main() {
+    let test_struct = dep::test_mod::TestStruct {};
+    test_struct.test_meth$0od()
+}
+//- /dep.rs crate:dep
+pub mod test_mod {
+    trait TestTrait {
+        fn test_method(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method(&self) {}
+    }
+}
+"#,
         );
     }
 
@@ -962,32 +971,32 @@ fn test_method(&self) {}
     fn not_applicable_for_imported_trait_for_method() {
         check_assist_not_applicable(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method(&self);
-                }
-                pub trait TestTrait2 {
-                    fn test_method(&self);
-                }
-                pub enum TestEnum {
-                    One,
-                    Two,
-                }
-                impl TestTrait2 for TestEnum {
-                    fn test_method(&self) {}
-                }
-                impl TestTrait for TestEnum {
-                    fn test_method(&self) {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method(&self);
+    }
+    pub trait TestTrait2 {
+        fn test_method(&self);
+    }
+    pub enum TestEnum {
+        One,
+        Two,
+    }
+    impl TestTrait2 for TestEnum {
+        fn test_method(&self) {}
+    }
+    impl TestTrait for TestEnum {
+        fn test_method(&self) {}
+    }
+}
 
-            use test_mod::TestTrait2;
-            fn main() {
-                let one = test_mod::TestEnum::One;
-                one.test$0_method();
-            }
-            ",
+use test_mod::TestTrait2;
+fn main() {
+    let one = test_mod::TestEnum::One;
+    one.test$0_method();
+}
+"#,
         )
     }
 
@@ -1114,7 +1123,7 @@ fn main() {}
     fn keep_generic_annotations_leading_colon() {
         check_assist(
             qualify_path,
-            r"
+            r#"
 //- /lib.rs crate:dep
 pub mod generic { pub struct Thing<'a, T>(&'a T); }
 
@@ -1122,7 +1131,7 @@ fn keep_generic_annotations_leading_colon() {
 fn foo() -> Thin$0g::<'static, ()> {}
 
 fn main() {}
-",
+"#,
             r"
 fn foo() -> dep::generic::Thing::<'static, ()> {}
 
@@ -1135,30 +1144,30 @@ fn main() {}
     fn associated_struct_const_generic() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub struct TestStruct<T> {}
-                impl<T> TestStruct<T> {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+            r#"
+mod test_mod {
+    pub struct TestStruct<T> {}
+    impl<T> TestStruct<T> {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                TestStruct::<()>::TEST_CONST$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub struct TestStruct<T> {}
-                impl<T> TestStruct<T> {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+fn main() {
+    TestStruct::<()>::TEST_CONST$0
+}
+"#,
+            r#"
+mod test_mod {
+    pub struct TestStruct<T> {}
+    impl<T> TestStruct<T> {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::<()>::TEST_CONST
-            }
-            ",
+fn main() {
+    test_mod::TestStruct::<()>::TEST_CONST
+}
+"#,
         );
     }
 
@@ -1166,36 +1175,36 @@ fn main() {
     fn associated_trait_const_generic() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    const TEST_CONST: u8;
-                }
-                pub struct TestStruct<T> {}
-                impl<T> TestTrait for TestStruct<T> {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        const TEST_CONST: u8;
+    }
+    pub struct TestStruct<T> {}
+    impl<T> TestTrait for TestStruct<T> {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                test_mod::TestStruct::<()>::TEST_CONST$0
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    const TEST_CONST: u8;
-                }
-                pub struct TestStruct<T> {}
-                impl<T> TestTrait for TestStruct<T> {
-                    const TEST_CONST: u8 = 42;
-                }
-            }
+fn main() {
+    test_mod::TestStruct::<()>::TEST_CONST$0
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        const TEST_CONST: u8;
+    }
+    pub struct TestStruct<T> {}
+    impl<T> TestTrait for TestStruct<T> {
+        const TEST_CONST: u8 = 42;
+    }
+}
 
-            fn main() {
-                <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
-            }
-            ",
+fn main() {
+    <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST
+}
+"#,
         );
     }
 
@@ -1203,38 +1212,62 @@ fn main() {
     fn trait_method_generic() {
         check_assist(
             qualify_path,
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method<T>(&self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method<T>(&self) {}
-                }
-            }
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method<T>(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method<T>(&self) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_struct.test_meth$0od::<()>()
-            }
-            ",
-            r"
-            mod test_mod {
-                pub trait TestTrait {
-                    fn test_method<T>(&self);
-                }
-                pub struct TestStruct {}
-                impl TestTrait for TestStruct {
-                    fn test_method<T>(&self) {}
-                }
-            }
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_struct.test_meth$0od::<()>()
+}
+"#,
+            r#"
+mod test_mod {
+    pub trait TestTrait {
+        fn test_method<T>(&self);
+    }
+    pub struct TestStruct {}
+    impl TestTrait for TestStruct {
+        fn test_method<T>(&self) {}
+    }
+}
 
-            fn main() {
-                let test_struct = test_mod::TestStruct {};
-                test_mod::TestTrait::test_method::<()>(&test_struct)
-            }
-            ",
+fn main() {
+    let test_struct = test_mod::TestStruct {};
+    test_mod::TestTrait::test_method::<()>(&test_struct)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn works_in_derives() {
+        check_assist(
+            qualify_path,
+            r#"
+//- minicore:derive
+mod foo {
+    #[rustc_builtin_macro]
+    pub macro Copy {}
+}
+#[derive(Copy$0)]
+struct Foo;
+"#,
+            r#"
+mod foo {
+    #[rustc_builtin_macro]
+    pub macro Copy {}
+}
+#[derive(foo::Copy)]
+struct Foo;
+"#,
         );
     }
 }