From 99906baa176985fe0f976ed0e2806a93b30532bc Mon Sep 17 00:00:00 2001
From: Lukas Wirth <lukastw97@gmail.com>
Date: Sun, 17 Oct 2021 12:58:37 +0200
Subject: [PATCH] Fix clippy attribute completions always prefixing with
 `clippy::`

---
 .../src/completions/attribute/lint.rs         | 21 ++++++++++++-------
 .../src/completions/attribute/repr.rs         |  2 +-
 crates/ide_completion/src/tests/attribute.rs  | 19 ++++++++++++++++-
 crates/rust-analyzer/tests/slow-tests/tidy.rs |  2 ++
 4 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs
index dffb2d92d38..4f7930d0dd9 100644
--- a/crates/ide_completion/src/completions/attribute/lint.rs
+++ b/crates/ide_completion/src/completions/attribute/lint.rs
@@ -1,6 +1,6 @@
 //! Completion for lints
 use ide_db::helpers::generated_lints::Lint;
-use syntax::ast;
+use syntax::{ast, T};
 
 use crate::{
     context::CompletionContext,
@@ -16,7 +16,7 @@ pub(super) fn complete_lint(
 ) {
     if let Some(existing_lints) = super::parse_comma_sep_paths(derive_input) {
         for &Lint { label, description } in lints_completions {
-            let (ex_q, ex_name) = {
+            let (qual, name) = {
                 // FIXME: change `Lint`'s label to not store a path in it but split the prefix off instead?
                 let mut parts = label.split("::");
                 let ns_or_label = match parts.next() {
@@ -29,7 +29,7 @@ pub(super) fn complete_lint(
                     None => (None, ns_or_label),
                 }
             };
-            let repr_already_annotated = existing_lints
+            let lint_already_annotated = existing_lints
                 .iter()
                 .filter_map(|path| {
                     let q = path.qualifier();
@@ -38,21 +38,26 @@ pub(super) fn complete_lint(
                     }
                     Some((q.and_then(|it| it.as_single_name_ref()), path.segment()?.name_ref()?))
                 })
-                .any(|(q, name)| {
-                    let qualifier_matches = match (q, ex_q) {
+                .any(|(q, name_ref)| {
+                    let qualifier_matches = match (q, qual) {
                         (None, None) => true,
                         (None, Some(_)) => false,
                         (Some(_), None) => false,
                         (Some(q), Some(ns)) => q.text() == ns,
                     };
-                    qualifier_matches && name.text() == ex_name
+                    qualifier_matches && name_ref.text() == name
                 });
-            if repr_already_annotated {
+            if lint_already_annotated {
                 continue;
             }
+            let insert = match qual {
+                Some(qual) if !ctx.previous_token_is(T![:]) => format!("{}::{}", qual, name),
+                _ => name.to_owned(),
+            };
             let mut item =
-                CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), ex_name);
+                CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
             item.kind(CompletionItemKind::Attribute)
+                .insert_text(insert)
                 .documentation(hir::Documentation::new(description.to_owned()));
             item.add_to(acc)
         }
diff --git a/crates/ide_completion/src/completions/attribute/repr.rs b/crates/ide_completion/src/completions/attribute/repr.rs
index 95efe77c06d..9a12b8571c7 100644
--- a/crates/ide_completion/src/completions/attribute/repr.rs
+++ b/crates/ide_completion/src/completions/attribute/repr.rs
@@ -23,7 +23,7 @@ pub(super) fn complete_repr(acc: &mut Completions, ctx: &CompletionContext, inpu
                 })
                 .any(|it| {
                     let text = it.text();
-                    label == text || collides.contains(&text.as_str())
+                    lookup.unwrap_or(label) == text || collides.contains(&text.as_str())
                 });
             if repr_already_annotated {
                 continue;
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index 7d0bdc58210..9d22bb196bd 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -692,6 +692,24 @@ mod lint {
             r#"#[feature(box_syntax)] struct Test;"#,
         )
     }
+
+    #[test]
+    fn lint_clippy_unqualified() {
+        check_edit(
+            "clippy::as_conversions",
+            r#"#[allow($0)] struct Test;"#,
+            r#"#[allow(clippy::as_conversions)] struct Test;"#,
+        );
+    }
+
+    #[test]
+    fn lint_clippy_qualified() {
+        check_edit(
+            "clippy::as_conversions",
+            r#"#[allow(clippy::$0)] struct Test;"#,
+            r#"#[allow(clippy::as_conversions)] struct Test;"#,
+        );
+    }
 }
 
 mod repr {
@@ -742,7 +760,6 @@ mod repr {
         check_repr(
             r#"#[repr(align(1), $0)] struct Test;"#,
             expect![[r#"
-            at align($0)
             at transparent
             at C
             at u8
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index bd34a5fda81..3866c178f8c 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -192,6 +192,8 @@ fn deny_clippy(path: &Path, text: &str) {
         "ide_db/src/helpers/generated_lints.rs",
         // The tests test clippy lint hovers
         "ide/src/hover/tests.rs",
+        // The tests test clippy lint completions
+        "ide_completion/src/tests/attribute.rs",
     ];
     if ignore.iter().any(|p| path.ends_with(p)) {
         return;