diff options
author | Kirill Bulatov <[email protected]> | 2020-11-11 09:37:41 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-11-12 11:46:02 +0000 |
commit | 335edf87bc84bdfcc48ab23f12f606ced09dbac7 (patch) | |
tree | 4415c7ec1d8dc1ca2e98f2d5243031356236ea8d | |
parent | 99fa139beab0c03583c676554c3d807525f602af (diff) |
Do not insert imports before inner comments
-rw-r--r-- | crates/assists/src/utils/insert_use.rs | 110 |
1 files changed, 92 insertions, 18 deletions
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index 84a0dffdd..c4de83f77 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -9,7 +9,7 @@ use syntax::{ | |||
9 | edit::{AstNodeEdit, IndentLevel}, | 9 | edit::{AstNodeEdit, IndentLevel}, |
10 | make, AstNode, PathSegmentKind, VisibilityOwner, | 10 | make, AstNode, PathSegmentKind, VisibilityOwner, |
11 | }, | 11 | }, |
12 | InsertPosition, SyntaxElement, SyntaxNode, | 12 | AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, |
13 | }; | 13 | }; |
14 | use test_utils::mark; | 14 | use test_utils::mark; |
15 | 15 | ||
@@ -63,27 +63,46 @@ impl ImportScope { | |||
63 | } | 63 | } |
64 | } | 64 | } |
65 | 65 | ||
66 | fn insert_pos_after_inner_attribute(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { | 66 | fn insert_pos_after_inner_elements(&self) -> (InsertPosition<SyntaxElement>, AddBlankLine) { |
67 | // check if the scope has inner attributes, we dont want to insert in front of them | 67 | let mut last_inner_element = None; |
68 | match self | 68 | |
69 | .as_syntax_node() | 69 | for maybe_inner_element in self.as_syntax_node().children_with_tokens() { |
70 | .children() | 70 | match maybe_inner_element { |
71 | // no flat_map here cause we want to short circuit the iterator | 71 | NodeOrToken::Node(maybe_inner_node) => { |
72 | .map(ast::Attr::cast) | 72 | if is_inner_node(maybe_inner_node.clone()) { |
73 | .take_while(|attr| { | 73 | last_inner_element = Some(NodeOrToken::Node(maybe_inner_node)) |
74 | attr.as_ref().map(|attr| attr.kind() == ast::AttrKind::Inner).unwrap_or(false) | 74 | } else { |
75 | }) | 75 | if let Some(maybe_inner_token) = maybe_inner_node.first_token() { |
76 | .last() | 76 | if is_inner_token(maybe_inner_token.clone()) { |
77 | .flatten() | 77 | last_inner_element = Some(NodeOrToken::Token(maybe_inner_token)) |
78 | { | 78 | } |
79 | Some(attr) => { | 79 | } |
80 | (InsertPosition::After(attr.syntax().clone().into()), AddBlankLine::BeforeTwice) | 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 | } | ||
81 | } | 87 | } |
88 | } | ||
89 | |||
90 | match last_inner_element { | ||
91 | Some(element) => (InsertPosition::After(element.into()), AddBlankLine::BeforeTwice), | ||
82 | None => self.first_insert_pos(), | 92 | None => self.first_insert_pos(), |
83 | } | 93 | } |
84 | } | 94 | } |
85 | } | 95 | } |
86 | 96 | ||
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 | |||
87 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 106 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
88 | pub(crate) fn insert_use<'a>( | 107 | pub(crate) fn insert_use<'a>( |
89 | scope: &ImportScope, | 108 | scope: &ImportScope, |
@@ -558,7 +577,7 @@ fn find_insert_position( | |||
558 | (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) | 577 | (InsertPosition::After(node.into()), AddBlankLine::BeforeTwice) |
559 | } | 578 | } |
560 | // there are no imports in this file at all | 579 | // 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(), |
562 | }, | 581 | }, |
563 | } | 582 | } |
564 | } | 583 | } |
@@ -830,12 +849,67 @@ use foo::bar;", | |||
830 | "foo::bar", | 849 | "foo::bar", |
831 | r"#![allow(unused_imports)] | 850 | r"#![allow(unused_imports)] |
832 | 851 | ||
852 | #![no_std] | ||
833 | fn main() {}", | 853 | fn main() {}", |
834 | r"#![allow(unused_imports)] | 854 | r"#![allow(unused_imports)] |
835 | 855 | ||
836 | use foo::bar; | 856 | #![no_std] |
837 | 857 | ||
858 | use foo::bar; | ||
838 | fn main() {}", | 859 | fn 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() {}"#, | ||
839 | ) | 913 | ) |
840 | } | 914 | } |
841 | 915 | ||