@@ -9,7 +9,7 @@ use syntax::{
99 edit:: { AstNodeEdit , IndentLevel } ,
1010 make, AstNode , PathSegmentKind , VisibilityOwner ,
1111 } ,
12- InsertPosition , SyntaxElement , SyntaxNode ,
12+ AstToken , InsertPosition , NodeOrToken , SyntaxElement , SyntaxNode , SyntaxToken ,
1313} ;
1414use test_utils:: mark;
1515
@@ -63,27 +63,46 @@ impl ImportScope {
6363 }
6464 }
6565
66- fn insert_pos_after_inner_attribute ( & self ) -> ( InsertPosition < SyntaxElement > , AddBlankLine ) {
67- // check if the scope has inner attributes, we dont want to insert in front of them
68- match self
69- . as_syntax_node ( )
70- . children ( )
71- // no flat_map here cause we want to short circuit the iterator
72- . map ( ast:: Attr :: cast)
73- . take_while ( |attr| {
74- attr. as_ref ( ) . map ( |attr| attr. kind ( ) == ast:: AttrKind :: Inner ) . unwrap_or ( false )
75- } )
76- . last ( )
77- . flatten ( )
78- {
79- Some ( attr) => {
80- ( InsertPosition :: After ( attr. syntax ( ) . clone ( ) . into ( ) ) , AddBlankLine :: BeforeTwice )
66+ fn insert_pos_after_inner_elements ( & self ) -> ( InsertPosition < SyntaxElement > , AddBlankLine ) {
67+ let mut last_inner_element = None ;
68+
69+ for maybe_inner_element in self . as_syntax_node ( ) . children_with_tokens ( ) {
70+ match maybe_inner_element {
71+ NodeOrToken :: Node ( maybe_inner_node) => {
72+ if is_inner_node ( maybe_inner_node. clone ( ) ) {
73+ last_inner_element = Some ( NodeOrToken :: Node ( maybe_inner_node) )
74+ } else {
75+ if let Some ( maybe_inner_token) = maybe_inner_node. first_token ( ) {
76+ if is_inner_token ( maybe_inner_token. clone ( ) ) {
77+ last_inner_element = Some ( NodeOrToken :: Token ( maybe_inner_token) )
78+ }
79+ }
80+ } ;
81+ }
82+ NodeOrToken :: Token ( maybe_inner_token) => {
83+ if is_inner_token ( maybe_inner_token. clone ( ) ) {
84+ last_inner_element = Some ( NodeOrToken :: Token ( maybe_inner_token) )
85+ }
86+ }
8187 }
88+ }
89+
90+ match last_inner_element {
91+ Some ( element) => ( InsertPosition :: After ( element. into ( ) ) , AddBlankLine :: BeforeTwice ) ,
8292 None => self . first_insert_pos ( ) ,
8393 }
8494 }
8595}
8696
97+ fn is_inner_node ( node : SyntaxNode ) -> bool {
98+ ast:: Attr :: cast ( node) . map ( |attr| attr. kind ( ) ) == Some ( ast:: AttrKind :: Inner )
99+ }
100+
101+ fn is_inner_token ( token : SyntaxToken ) -> bool {
102+ ast:: Comment :: cast ( token) . and_then ( |comment| comment. kind ( ) . doc )
103+ == Some ( ast:: CommentPlacement :: Inner )
104+ }
105+
87106/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
88107pub ( crate ) fn insert_use < ' a > (
89108 scope : & ImportScope ,
@@ -558,7 +577,7 @@ fn find_insert_position(
558577 ( InsertPosition :: After ( node. into ( ) ) , AddBlankLine :: BeforeTwice )
559578 }
560579 // there are no imports in this file at all
561- None => scope. insert_pos_after_inner_attribute ( ) ,
580+ None => scope. insert_pos_after_inner_elements ( ) ,
562581 } ,
563582 }
564583 }
@@ -830,12 +849,67 @@ use foo::bar;",
830849 "foo::bar" ,
831850 r"#![allow(unused_imports)]
832851
852+ #![no_std]
833853fn main() {}" ,
834854 r"#![allow(unused_imports)]
835855
836- use foo::bar;
856+ #![no_std]
837857
858+ use foo::bar;
838859fn main() {}" ,
860+ ) ;
861+ }
862+
863+ #[ test]
864+ fn inserts_after_single_line_inner_comments ( ) {
865+ check_none (
866+ "foo::bar::Baz" ,
867+ "//! Single line inner comments do not allow any code before them." ,
868+ r#"//! Single line inner comments do not allow any code before them.
869+
870+ use foo::bar::Baz;"# ,
871+ ) ;
872+ }
873+
874+ #[ test]
875+ fn inserts_after_multiline_inner_comments ( ) {
876+ check_none (
877+ "foo::bar::Baz" ,
878+ r#"/*! Multiline inner comments do not allow any code before them. */
879+
880+ /*! RA considers this inner comment belonging to the function, yet we still cannot place the code before it. */
881+ fn main() {}"# ,
882+ r#"/*! Multiline inner comments do not allow any code before them. */
883+
884+ /*! RA considers this inner comment belonging to the function, yet we still cannot place the code before it. */
885+
886+ use foo::bar::Baz;
887+ fn main() {}"# ,
888+ )
889+ }
890+
891+ #[ test]
892+ fn inserts_after_all_inner_items ( ) {
893+ check_none (
894+ "foo::bar::Baz" ,
895+ r#"#![allow(unused_imports)]
896+ /*! Multiline line comment 2 */
897+
898+
899+ //! Single line comment 1
900+ #![no_std]
901+ //! Single line comment 2
902+ fn main() {}"# ,
903+ r#"#![allow(unused_imports)]
904+ /*! Multiline line comment 2 */
905+
906+
907+ //! Single line comment 1
908+ #![no_std]
909+ //! Single line comment 2
910+
911+ use foo::bar::Baz;
912+ fn main() {}"# ,
839913 )
840914 }
841915
0 commit comments