Repository: rust-lang/rust-analyzer
Pull request #12197 (2022-05-09 09:53:22)

fix: Fix import insertion inserting after last comment in a file

Veykril: @bors r+
bors: :pushpin: Commit 131e8c8f8287b8235ee4005414c10a3964020483 has been approved by `Veykril`

<!-- @bors r=Veykril 131e8c8f8287b8235ee4005414c10a3964020483 -->
<!-- homu: {"type":"Approved","sha":"131e8c8f8287b8235ee4005414c10a3964020483","approver":"Veykril"} -->
bors: :hourglass: Testing commit 131e8c8f8287b8235ee4005414c10a3964020483 with merge 92ca9289d32b3e84c12647b4573376dd9766d049...
<!-- homu: {"type":"BuildStarted","head_sha":"131e8c8f8287b8235ee4005414c10a3964020483","merge_sha":"92ca9289d32b3e84c12647b4573376dd9766d049"} -->
bors: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang/rust-analyzer/runs/6349703488?check_suite_focus=true)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang/rust-analyzer/runs/6349703488?check_suite_focus=true","builder_name":"checks-actions"} -->
Veykril: @bors r+
bors: :pushpin: Commit a0bc5665a3eec0253ceb42578db314fee91cae46 has been approved by `Veykril`

<!-- @bors r=Veykril a0bc5665a3eec0253ceb42578db314fee91cae46 -->
<!-- homu: {"type":"Approved","sha":"a0bc5665a3eec0253ceb42578db314fee91cae46","approver":"Veykril"} -->

Patch:
diff --git a/crates/hir-def/src/builtin_attr.rs b/crates/hir-def/src/builtin_attr.rs
index 9aad996a84..3f43111fb1 100644
--- a/crates/hir-def/src/builtin_attr.rs
+++ b/crates/hir-def/src/builtin_attr.rs
@@ -274,7 +274,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
     ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")),
     // FIXME(#14407) -- only looked at on-demand so we can't
     // guarantee they'll have already been checked.
-    // FIXME(jhpratt) remove this when #[rustc_deprecated] is fully removed from the compiler
     ungated!(
         rustc_deprecated, AssumedUsed,
         template!(List: r#"since = "version", reason = "...""#)
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index b09e4a6320..01c9bfdb85 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -67,7 +67,7 @@ impl<'a> RenderContext<'a> {
 
     fn is_deprecated(&self, def: impl HasAttrs) -> bool {
         let attrs = def.attrs(self.db());
-        attrs.by_key("deprecated").exists()
+        attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
     }
 
     fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
@@ -675,6 +675,8 @@ fn main() { let _: m::Spam = S$0 }
             r#"
 #[deprecated]
 fn something_deprecated() {}
+#[rustc_deprecated(since = "1.0.0")]
+fn something_else_deprecated() {}
 
 fn main() { som$0 }
 "#,
@@ -683,8 +685,8 @@ fn main() { som$0 }
                 [
                     CompletionItem {
                         label: "main()",
-                        source_range: 56..59,
-                        delete: 56..59,
+                        source_range: 127..130,
+                        delete: 127..130,
                         insert: "main()$0",
                         kind: SymbolKind(
                             Function,
@@ -694,8 +696,8 @@ fn main() { som$0 }
                     },
                     CompletionItem {
                         label: "something_deprecated()",
-                        source_range: 56..59,
-                        delete: 56..59,
+                        source_range: 127..130,
+                        delete: 127..130,
                         insert: "something_deprecated()$0",
                         kind: SymbolKind(
                             Function,
@@ -704,6 +706,18 @@ fn main() { som$0 }
                         detail: "fn()",
                         deprecated: true,
                     },
+                    CompletionItem {
+                        label: "something_else_deprecated()",
+                        source_range: 127..130,
+                        delete: 127..130,
+                        insert: "something_else_deprecated()$0",
+                        kind: SymbolKind(
+                            Function,
+                        ),
+                        lookup: "something_else_deprecated",
+                        detail: "fn()",
+                        deprecated: true,
+                    },
                 ]
             "#]],
         );
diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs
index a19969ecc4..66d0b2ee82 100644
--- a/crates/ide-db/src/imports/insert_use.rs
+++ b/crates/ide-db/src/imports/insert_use.rs
@@ -8,7 +8,7 @@ use hir::Semantics;
 use syntax::{
     algo,
     ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind},
-    ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
+    ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode,
 };
 
 use crate::{
@@ -397,12 +397,16 @@ fn insert_use_(
     }
 
     // there are no imports in this file at all
+    // so put the import after all inner module attributes and possible license header comments
     if let Some(last_inner_element) = scope_syntax
         .children_with_tokens()
-        .filter(|child| match child {
+        .take_while(|child| match child {
             NodeOrToken::Node(node) => is_inner_attribute(node.clone()),
-            NodeOrToken::Token(token) => is_comment(token.clone()),
+            NodeOrToken::Token(token) => {
+                [SyntaxKind::WHITESPACE, SyntaxKind::COMMENT].contains(&token.kind())
+            }
         })
+        .filter(|child| child.as_token().map_or(true, |t| t.kind() != SyntaxKind::WHITESPACE))
         .last()
     {
         cov_mark::hit!(insert_empty_inner_attr);
@@ -439,7 +443,3 @@ fn insert_use_(
 fn is_inner_attribute(node: SyntaxNode) -> bool {
     ast::Attr::cast(node).map(|attr| attr.kind()) == Some(ast::AttrKind::Inner)
 }
-
-fn is_comment(token: SyntaxToken) -> bool {
-    ast::Comment::cast(token).is_some()
-}


Test patch:
diff --git a/crates/ide-db/src/imports/insert_use/tests.rs b/crates/ide-db/src/imports/insert_use/tests.rs
index acadb353b6..6569e4ed8c 100644
--- a/crates/ide-db/src/imports/insert_use/tests.rs
+++ b/crates/ide-db/src/imports/insert_use/tests.rs
@@ -5,6 +5,24 @@ use test_utils::{assert_eq_text, CURSOR_MARKER};
 
 use super::*;
 
+#[test]
+fn trailing_comment_in_empty_file() {
+    check(
+        "foo::bar",
+        r#"
+struct Struct;
+// 0 = 1
+"#,
+        r#"
+use foo::bar;
+
+struct Struct;
+// 0 = 1
+"#,
+        ImportGranularity::Crate,
+    );
+}
+
 #[test]
 fn respects_cfg_attr_fn() {
     check(