about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ide-assists/src/handlers/extract_module.rs190
1 files changed, 188 insertions, 2 deletions
diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs
index 11349b45d3c..154856df548 100644
--- a/crates/ide-assists/src/handlers/extract_module.rs
+++ b/crates/ide-assists/src/handlers/extract_module.rs
@@ -19,7 +19,7 @@ use syntax::{
         make, HasName, HasVisibility,
     },
     match_ast, ted, AstNode, SourceFile,
-    SyntaxKind::WHITESPACE,
+    SyntaxKind::{self, WHITESPACE},
     SyntaxNode, TextRange,
 };
 
@@ -380,7 +380,16 @@ impl Module {
         }
 
         for (vis, syntax) in replacements {
-            add_change_vis(vis, syntax.first_child_or_token());
+            let item = syntax.children_with_tokens().find(|node_or_token| {
+                match node_or_token.kind() {
+                    // We're skipping comments, doc comments, and attribute macros that may precede the keyword
+                    // that the visibility should be placed before.
+                    SyntaxKind::COMMENT | SyntaxKind::ATTR | SyntaxKind::WHITESPACE => false,
+                    _ => true,
+                }
+            });
+
+            add_change_vis(vis, item);
         }
     }
 
@@ -1581,4 +1590,181 @@ mod modname {
         ",
         )
     }
+
+    #[test]
+    fn test_issue_12790() {
+        check_assist(
+            extract_module,
+            r"
+            $0/// A documented function
+            fn documented_fn() {}
+
+            // A commented function with a #[] attribute macro
+            #[cfg(test)]
+            fn attribute_fn() {}
+
+            // A normally commented function
+            fn normal_fn() {}
+
+            /// A documented Struct
+            struct DocumentedStruct {
+                // Normal field
+                x: i32,
+
+                /// Documented field
+                y: i32,
+
+                // Macroed field
+                #[cfg(test)]
+                z: i32,
+            }
+
+            // A macroed Struct
+            #[cfg(test)]
+            struct MacroedStruct {
+                // Normal field
+                x: i32,
+
+                /// Documented field
+                y: i32,
+
+                // Macroed field
+                #[cfg(test)]
+                z: i32,
+            }
+
+            // A normal Struct
+            struct NormalStruct {
+                // Normal field
+                x: i32,
+
+                /// Documented field
+                y: i32,
+
+                // Macroed field
+                #[cfg(test)]
+                z: i32,
+            }
+
+            /// A documented type
+            type DocumentedType = i32;
+
+            // A macroed type
+            #[cfg(test)]
+            type MacroedType = i32;
+
+            /// A module to move
+            mod module {}
+
+            /// An impl to move
+            impl NormalStruct {
+                /// A method
+                fn new() {}
+            }
+
+            /// A documented trait
+            trait DocTrait {
+                /// Inner function
+                fn doc() {}
+            }
+
+            /// An enum
+            enum DocumentedEnum {
+                /// A variant
+                A,
+                /// Another variant
+                B { x: i32, y: i32 }
+            }
+
+            /// Documented const
+            const MY_CONST: i32 = 0;$0
+        ",
+            r"
+            mod modname {
+                /// A documented function
+                pub(crate) fn documented_fn() {}
+
+                // A commented function with a #[] attribute macro
+                #[cfg(test)]
+                pub(crate) fn attribute_fn() {}
+
+                // A normally commented function
+                pub(crate) fn normal_fn() {}
+
+                /// A documented Struct
+                pub(crate) struct DocumentedStruct {
+                    // Normal field
+                    pub(crate) x: i32,
+
+                    /// Documented field
+                    pub(crate) y: i32,
+
+                    // Macroed field
+                    #[cfg(test)]
+                    pub(crate) z: i32,
+                }
+
+                // A macroed Struct
+                #[cfg(test)]
+                pub(crate) struct MacroedStruct {
+                    // Normal field
+                    pub(crate) x: i32,
+
+                    /// Documented field
+                    pub(crate) y: i32,
+
+                    // Macroed field
+                    #[cfg(test)]
+                    pub(crate) z: i32,
+                }
+
+                // A normal Struct
+                pub(crate) struct NormalStruct {
+                    // Normal field
+                    pub(crate) x: i32,
+
+                    /// Documented field
+                    pub(crate) y: i32,
+
+                    // Macroed field
+                    #[cfg(test)]
+                    pub(crate) z: i32,
+                }
+
+                /// A documented type
+                pub(crate) type DocumentedType = i32;
+
+                // A macroed type
+                #[cfg(test)]
+                pub(crate) type MacroedType = i32;
+
+                /// A module to move
+                pub(crate) mod module {}
+
+                /// An impl to move
+                impl NormalStruct {
+                    /// A method
+                    pub(crate) fn new() {}
+                }
+
+                /// A documented trait
+                pub(crate) trait DocTrait {
+                    /// Inner function
+                    fn doc() {}
+                }
+
+                /// An enum
+                pub(crate) enum DocumentedEnum {
+                    /// A variant
+                    A,
+                    /// Another variant
+                    B { x: i32, y: i32 }
+                }
+
+                /// Documented const
+                pub(crate) const MY_CONST: i32 = 0;
+            }
+        ",
+        )
+    }
 }