ide_completion/completions/attribute/
lint.rs1use ide_db::{
3 SymbolKind,
4 documentation::Documentation,
5 generated::lints::{CLIPPY_LINT_GROUPS, CLIPPY_LINTS, DEFAULT_LINTS, Lint, RUSTDOC_LINTS},
6};
7use syntax::ast;
8
9use crate::{Completions, context::CompletionContext, item::CompletionItem};
10
11pub(super) fn complete_lint(
12 acc: &mut Completions,
13 ctx: &CompletionContext<'_, '_>,
14 is_qualified: bool,
15 existing_lints: &[ast::Path],
16) {
17 let lints = (CLIPPY_LINT_GROUPS.iter().map(|g| &g.lint))
18 .chain(DEFAULT_LINTS)
19 .chain(CLIPPY_LINTS)
20 .chain(RUSTDOC_LINTS);
21
22 for &Lint { label, description, .. } in lints {
23 let (qual, name) = match label.split_once("::") {
25 Some((qual, name)) => (Some(qual), name),
26 None => (None, label),
27 };
28 if qual.is_none() && is_qualified {
29 continue;
31 }
32 let lint_already_annotated = existing_lints
33 .iter()
34 .filter_map(|path| {
35 let q = path.qualifier();
36 if q.as_ref().and_then(|it| it.qualifier()).is_some() {
37 return None;
38 }
39 Some((q.and_then(|it| it.as_single_name_ref()), path.segment()?.name_ref()?))
40 })
41 .any(|(q, name_ref)| {
42 let qualifier_matches = match (q, qual) {
43 (None, None) => true,
44 (None, Some(_)) => false,
45 (Some(_), None) => false,
46 (Some(q), Some(ns)) => q.text() == ns,
47 };
48 qualifier_matches && name_ref.text() == name
49 });
50 if lint_already_annotated {
51 continue;
52 }
53 let label = match qual {
54 Some(qual) if !is_qualified => format!("{qual}::{name}"),
55 _ => name.to_owned(),
56 };
57 let mut item =
58 CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition);
59 item.documentation(Documentation::new_borrowed(description));
60 item.add_to(acc, ctx.db)
61 }
62}